`
Arron.li
  • 浏览: 136541 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

浅谈非静态内部类不能有静态成员

    博客分类:
  • Java
阅读更多

1 非静态内部类为什么不能有静态成员,我自己总结了下,

如下代码

public class OuterClass{
     class InnerClass{
         private static int i;
     }
}

 对于java类加载顺序我们知道,首先加载类,执行static变量初始化,接下来执行对象的创建,如果我们要执行代码中的变量i初始化,

那么必须先执行加载OuterClass,再加载Innerclass,最后初始化静态变量i,问题就出在加载Innerclass上面,我们可以把InnerClass看成OuterClass的非静态成员,它的初始化必须在外部类对象创建后以后进行,要加载InnerClass必须在实例化OuterClass之后完成 ,java虚拟机要求所有的静态变量必须在对象创建之前完成,这样便产生了矛盾。

Verion 0.11:

对于红色标记的部分,当时理解上有误,我们知道InnerClass可以有静态常量(static final),那么InnerClass类加载一定在OuterClass对象创建之前完成,但这还不足以说明为什么非静态内部类里面不能有静态的变量(基本类型 或对象因用),这里面涉及到Java语言的定义以及JVM的类加载的原理方面的知识,我将进一步研究这个问题,技术是严谨的,也希望各位读者提出宝贵的意见。

 

下面是我验证的代码解释InnerClass加载是在OuterClass对象创建之前完成的:

public class OuterClass {
	
	static int k = printI();
	
	static int printI(){
		System.out.println("Inner Class is loading before creating OuterClass instance");
		return InnerClass.i ;
	}
	
	OuterClass(){
		System.out.println("OuterClass constructor");
	}
	
	class InnerClass{
		private static final int i = 1;
		
	}
	public static void main(String[] args) {
		OuterClass o;
	}
}
//* out:
// Inner Class is loading before creating OuterClass instance
 

2 静态内部类可以有静态成员:

我们可以把静态内部类作为外部类OuterClass的一个静态成员,在执行类加载过程中,静态内部类在加载OuterClass后会进行初始化,同样的原理,静态内部类的静态成员也将被初始化,进行内存的分配,注意到,这时无论是内部类还是外部类,对象都没有实例化,这也说明了非静态内部类为什么不能有静态成员的原因。

public class OuterClass{
     static class InnerClass{
         private static int i;
     }
}
分享到:
评论
17 楼 logic 2010-06-14  
对"非静态内部类不能有静态成员"发表一下自己的见解,还请大家多指教。

其实,根本原因在于sun怎么设计内部类怎么依附于外部类这个关系。
(大家可以对内部类抽象成为外部类的一个局部域,不要束缚在单独类的基本概念上,在这里是一个特殊类了。)

实际把非静态内部类比做外部类的非静态方法容易理解一点,原因和在非静态方法中定义静态成员一个道理。
 
16 楼 Arron.li 2010-05-19  
快乐柠檬 写道
    
 class OuterClass{   
	 {
		 System.out.println(InnerClass.i);//在OuterClass类内部可能会访问InnerClass的静态成员,不保证InnerClass已初始化
		 System.out.println(InnerClass.ii);
	 }
	     class InnerClass{   
	         private static int i;  //error
	         static final int ii=1;//OK,编译器常量,不需要对InnerClass初始化就可以读取
	     }   
}


这是因为static final是编译期常量,类加载之前就已经分配内存。
15 楼 raito_yagami 2010-05-18  
回去翻翻 thinking in java 你就明白了
14 楼 快乐柠檬 2010-05-18  
    
 class OuterClass{   
	 {
		 System.out.println(InnerClass.i);//在OuterClass类内部可能会访问InnerClass的静态成员,不保证InnerClass已初始化
		 System.out.println(InnerClass.ii);
	 }
	     class InnerClass{   
	         private static int i;  //error
	         static final int ii=1;//OK,编译器常量,不需要对InnerClass初始化就可以读取
	     }   
}

13 楼 Arron.li 2010-05-18  
再次纠正问题:
引用
对于红色标记的部分,当时理解上有误,我们知道 InnerClass可以有静态常量(static final),那么InnerClass类加载一定在OuterClass对象创建之前完成

通过进一步研究类加载的原理,我们知道Class对象仅在需要时才会被加载,static初始化是在类加载进行的,所以当我们没有使用内部类时不会加载,也就是说外部类的加载与创建于内部类的加载没有必然的联系,我们现在解释为什么非静态内部类不能有静态成员(排除静态常量)是一种java的约定,可能是sun程序员用以有别于静态内部类的考虑。
下面是解释Class对象仅在需要时才会被加载的例子:
class Candy {
  static { print("Loading Candy"); }
}

class Gum {
  static { print("Loading Gum"); }
}

class Cookie {
  static { print("Loading Cookie"); }
}

public class SweetShop {
  public static void main(String[] args) {	
    print("inside main");
    new Candy();
    print("After creating Candy");
    try {
      Class.forName("Gum");
    } catch(ClassNotFoundException e) {
      print("Couldn't find Gum");
    }
    print("After Class.forName(\"Gum\")");
    new Cookie();
    print("After creating Cookie");
  }
} /* Output:
inside main
Loading Candy
After creating Candy
Loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
*///:~
12 楼 czpsailer 2010-05-07  
<pre name="code" class="java"> public class OuterClass {
public class InnerClass {
//基本数据类型和String,可以
static final int i = 0;
static final byte b = 0;
static final String str = "";
static final long l = 0;
static final double d = 0;
static final char c = 0;
static final short s = 0;
static final boolean bool = true;
static final float f = 0;
           
//其他类型对象,不可以
static final Object object = null; //这里编译错误
}
}</pre>
11 楼 Aoogoo 2010-05-07  
等lz研究清楚了,再来给我们讲解
10 楼 coffeesweet 2010-05-07  
final定义了常量,可以直接初始化
9 楼 Arron.li 2010-05-07  
查了下sun公司java language specification,提到内部类的规范:
Inner classes may not declare static initializers (§8.7)  or member interfaces. Inner classes may not declare static members, unless they are compile-time constant fields (§15.28).

对于非静态内部,可以有编译常量,不过至于为什么,还有待于进一步研究。
参考网址:http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3
8 楼 realcbb 2010-05-07  
关注这个问题.非静态内部类的final静态成员是何时初始化的?
singleton有一种写法就是这样的,这种写法到底是否比饿汉式好一直没搞清楚.
7 楼 chenxr 2010-05-07  
加final变量为常量了,这要区别 静态常量 与 静态变量 吧
6 楼 玲cc 2010-05-07  
为什么ls的这种写法可以呢?
求教了
5 楼 Arron.li 2010-05-06  
Agrael 写道
Arron.li 写道
Agrael 写道
    public class OuterClass{  
         class InnerClass{  
             private static final int i = 1;  
         }  
    }  

这样写。

首先static 成员不直接赋值同样也会完成自动初始化,楼上的写法没有本质的区别。


呵呵,这个区别大了,你去试下吧。

才看清楚,原来多了个final,回去好好研究下,谢谢你
4 楼 Agrael 2010-05-06  
Arron.li 写道
Agrael 写道
    public class OuterClass{  
         class InnerClass{  
             private static final int i = 1;  
         }  
    }  

这样写。

首先static 成员不直接赋值同样也会完成自动初始化,楼上的写法没有本质的区别。


呵呵,这个区别大了,你去试下吧。
3 楼 Arron.li 2010-05-06  
Agrael 写道
    public class OuterClass{  
         class InnerClass{  
             private static final int i = 1;  
         }  
    }  

这样写。

首先static 成员不直接赋值同样也会完成自动初始化,楼上的写法没有本质的区别。
2 楼 Agrael 2010-05-06  
    public class OuterClass{  
         class InnerClass{  
             private static final int i = 1;  
         }  
    }  

这样写。
1 楼 Arron.li 2010-05-06  
对于非静态内部类不能有静态成员,核心问题是在内部类的加载原理,个人认为执行内部类加载,是在外部类对象创建之后。

相关推荐

    浅谈内部类与静态内部类的应用

    与普通成员内部类不同,静态内部类不持有对外部类的引用,因此不能直接访问外部类的非静态成员。静态内部类需要通过外部类名.静态内部类名的方式来创建对象,这与访问任何其他静态成员的方式相同。这种特性使得静态...

    浅谈Java内部类的四个应用场景

    Java中的内部类分为静态内部类(Static Inner Class)和非静态内部类(Non-static Inner Class),非静态内部类又包括成员内部类(Member Inner Class)、局部内部类(Local Inner Class)以及匿名内部类(Anonymous...

    浅谈Java内部类——静态内部类

    静态内部类可以访问外部类的静态成员变量和静态方法,但不能访问外部类的非静态成员变量和方法。 优点和缺点 ---------- 静态内部类的优点是: * 它可以独立存在和实例化,不需要创建外部类的实例。 * 它可以访问...

    浅谈PHP中静态方法和非静态方法的相互调用

    静态方法不能访问非静态成员,因为静态方法属于类本身,而非静态方法属于类的对象。静态方法通常用于执行与类的任何具体实例无关的操作。 2. 非静态方法(non-static method): 非静态方法也称为实例方法,需要先...

    Java反射技术浅谈 (1).pdf

    Java反射技术浅谈 Java反射技术是一种可以访问、检测和修改程序本身状态或行为的能力。通过反射,Java程序可以加载一个运行时才知道名称的类,得到其完整内部信息,并创建其对象,或对其属性设值,或调用其方法。...

    浅谈C#基础之类的访问修饰符

    静态成员不能引用非静态成员,因为非静态成员依赖于特定的实例。 在继承关系中,访问修饰符的行为会有所不同。例如,当一个类(如`B`)继承自`TestClass`,并尝试访问`c`时,由于`c`在`B`中是`private`的(尽管在`...

    深入浅出谈java修饰符共6页.pdf.zip

    然而,提供的压缩包文件"深入浅出谈java修饰符共6页.pdf.zip"似乎包含的是一个PDF文档,若要获取更多具体信息,需要解压并查看文档内容。在"赚钱项目"这个子文件中,可能涉及的是如何利用Java编程技能进行项目开发以...

    浅谈Java中父类与子类的加载顺序详解

    这包括执行父类的非静态变量初始化(如果有的话)、初始化块以及构造器。在这个例子中,父类的非静态变量"p_Field"在初始化块中被初始化,接着执行初始化块的代码,然后调用父类的构造器。注意,即使子类没有显式地...

    浅谈C++对象的内存分布和虚函数表

    相反,静态数据成员不隶属于任何特定对象,而是作为类级别的变量,在程序的静态数据区仅存储一份。成员函数,无论是静态还是非静态,其代码体都存储在程序的代码段中,不占用对象的内存空间,因为它们是所有对象共享...

    浅谈C#中的常量、类型推断和作用域

    4. 静态成员作用域:静态变量属于类本身,而非类的实例,因此在整个程序运行期间都有效。 例如: ```csharp class ScopeExample { static int globalVar = 10; // 全局静态变量 void LocalScope() { int ...

    侯捷- -深入浅出MFC

    静态成员(变量与函数) C++程序的生与死:兼谈构造函数与解构函数 四种不同的对象生存方式(in stack、in heap、global、local static) 执行期类型信息(RTTI) 动态生成(Dynamic Creation) 异常处理(Exception...

    深入浅出MFC【侯捷】

    第2章 C++的重要性质 类及其成员——谈封装(encapsulation) 基类与派生类:谈继承(Inheritance) this指针 虚拟函数与多态(Polymorphism) 类与对象大解剖 Object slicing与虚拟函数 静态成员(变量与函数) ...

    冲刺BAT练习题

    - 构造函数和静态成员函数不能是虚函数。 6. **构造函数中能否调用虚函数** - 在构造函数中调用虚函数时,实际调用的是基类的虚函数版本,因为此时派生类的虚函数指针尚未初始化。 7. **C++中虚继承的作用及底层...

    JAVA面试指南

    - **接口**只能包含抽象方法和默认方法,不能有构造器。 - **抽象类**可以包含构造器、抽象方法、具体方法和实例变量。 - **5.3 运行时异常和一般异常的区别:** - **运行时异常**通常是由编程错误引起的,如数...

    C,C++经典推荐博文汇总

    在C++中,从函数返回内部静态成员的引用或指针时,需要注意生命周期管理,避免返回已销毁的对象引用,造成未定义行为。 #### C语言中sizeof()的用法 `sizeof`运算符用于获取变量或数据类型所占用的字节数,是理解和...

    传智播客扫地僧视频讲义源码

    26_静态成员变量和静态成员函数 27_C++面向对象模型初探_传智扫地僧 28_this指针 29_作业 源码及文档 01_上一次课程回顾 02_const修饰的是谁_传智扫地僧 03_this的const修饰课堂答疑 04_全局函数pk成员函数(返回...

    Python核心编程(第二版).pdf (压缩包分2部分,第二部分)

     6.20 *拷贝python对象、浅拷贝和深拷贝   6.21 序列类型小结   6.22 练习   第7章 映像和集合类型   7.1 映射类型:字典   7.1.1 如何创建字典和给字典赋值   7.1.2 如何访问字典中的值   ...

    Python核心编程(第二版).pdf (压缩包分2部分,第一部分)

     6.20 *拷贝python对象、浅拷贝和深拷贝   6.21 序列类型小结   6.22 练习   第7章 映像和集合类型   7.1 映射类型:字典   7.1.1 如何创建字典和给字典赋值   7.1.2 如何访问字典中的值   ...

Global site tag (gtag.js) - Google Analytics