根据成员内部类的定义:
- 首先生成外部类的实例对象
- 然后生成绑定到外部类实例对象的成员内部类实例对象
外部类实例对象的生成一定要先于成员内部类实例对象的生成
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外部类的实例对象的时候便生成了。这样这个成员内部类就脱离了外部类的掌控,不需要外部类的对象就可以生成内部类的对象,这与成员内部类的定义就相驳了,因为我们知道成员内部类的对象必须是先有外部类的对象才能创建,成员内部类的对象 脱离了其外部类的对象 就不会存在,并且是绑定在一起的,所以成员内部类不可以定义静态变量。
第四种情况与第三种情况相同原因。
程序运行结果: