成员内部类为什么不能定义静态属性和静态方法
根据成员内部类的定义:
- 首先生成外部类的实例对象
- 然后生成绑定到外部类实例对象的成员内部类实例对象
外部类实例对象的生成一定要先于成员内部类实例对象的生成
public class InnerClassDemo{ //对于final修饰的成员变量,说明该变量是只读变量,只能进行一次赋值操作,只能存在以下两种赋值情况,在这两个地方我们必须给它们赋初值。 //1)声明该成员变量时赋值: // a)如果表达式的值是常量表达式(返回基本类型数据),则编译器编译时就计算出该表达式的值,知道该值,那么编译器就可能会在编译时期优化程序 // b)如果不是常量表达式(返回引用类型数据),则编译器编译时,就不知道该值。 //2)在构造方法中赋值,运行时赋值,则编译器编译时,就不知道该值 //实例成员被默认初始化为0 int x; //static final修饰的变量必须被显示初始化,要么在声明时赋值初始化,要么在静态块中初始化。 //否则,语法错误 static final int i; static int y;//可以不用初始化,系统会默认赋值0 static final int j=2; //静态块,当类被JVM加载到内存时,静态块的静态代码执行。 static{ i=1; System.out.println("i="+i); System.out.println("j="+j); } public static void main(String[] args){ InnerClassDemo innerclassdemo=new InnerClassDemo(); InnerClass innerClass=innerclassdemo.new InnerClass(); System.out.println("innerclassdemo中x和y的默认值分别是是:"+innerclassdemo.x+y); System.out.println("innerClass中i="+innerClass.i); System.out.println("innerClass中str="+innerClass.str); System.out.println("Welcome!"); } class InnerClass{ //1.在成员内部类中,只有编译器在编译的时候赋值号右边是常量表达式(编译时,可以计算出表达式的基本类型值), //左边是只读静态常量的情况才可以存在静态只读常量 //然后编译器把它当做编译器常量来使用,其实说白了就是和这个外部类的实例无关。 static final int i=50; static final String str=s; //2.以下均不可以 //2.1虽然static final为只读静态变量,但是是在构造方法中运行时赋值,编译时不知道其值。 //static final int i; //static final String str //2.2虽然static final为只读静态变量,但是赋值号右边不是常量表达式(返回引用类型数据),编译时并不知道其引用的实例值。 //static final String str=new String(""); //3.没有外部类实例,此内部类不需要外部类实例就初始化了变量,与成员内部类的定义相悖。 //static InnerClass innerClass=new InnerClass(); //4.静态方法中,但是没有外部类实例 //static void method(){ // InnerClass innerClass=new InnerClass(); // }
综上,其实内部类并不是完全不能出现static这样的修饰的,只要符合第一种情况的就是可以的。
编译器其实无法区分第二种,第三种情况的,第三种的情况肯定是不行的与内部成员类的定义相驳,所以第二种情况在语法上也被禁止了。
第三种情况,根据初始化的流程我们知道,在类加载的时候,static变量就必须被显式初始化,那么我们InnerClass成员内部类的实例对象在没InnerClassDemo外部类的实例对象的时候便生成了。这样这个成员内部类就脱离了外部类的掌控,不需要外部类的对象就可以生成内部类的对象,这与成员内部类的定义就相驳了,因为我们知道成员内部类的对象必须是先有外部类的对象才能创建,成员内部类的对象 脱离了其外部类的对象 就不会存在,并且是绑定在一起的,所以成员内部类不可以定义静态变量。
第四种情况与第三种情况相同原因。
程序运行结果: