为了尽可能阐述清楚这个问题,我会从一下几个方向说明这个问题:
1、 测试用例
* 测试非静态内部类如何理解?
* 测试非静态内部类定义静态成员是否合法?
* 测试非静态内部类是否可以定义静态常量?
a、定义字面常量
b、定义动态常量
2、 测试结果
3、 探究缘由
测试方案:
测试非静态内部类如何理解?
代码用例:
结论:我们理解非静态内部类时,可以看作是一个外部类的一个非静态成员,那么其实非静态内部类就是隶属于外部类对象的,但是它就其本质还是一个类。只要把握住这个两个核心接下来的内容就很好理解了。所以这也是为什么在TestInner类中测试使用Inner时,我门需要创建外部类对象之后才能使用内部类对象,因为:
内部类是属于外部类对象的,其次内部类的非静态内容访问也需要内部类对象,所以要new 外部类.new 内部类
测试方案:
测试非静态内部类定义静态成员是否合法?
代码用例:
结论:我们在测试在非静态内部类中说明静态内容时,会直接报错,此时这是为什么呢?
第一:java虚拟机要求所有的静态变量在类加载过程中的初始化阶段将符号引用变为直接引用。我们简单可以理解为:此时还没有对象呢!那么这也意味着我在内部类中定义的静态内容,要先于内部类对象存在。因为它是类层面上的
第二:由于内部类时依附于外部类对象的,那么也就意味着内部类中的内容时依附于外部类的对象的。但是内部类中的静态内容是不需要实例就可以,上述第一条已经说过了,但是由于第二条我们刚说的内部类时依附于外部类的,也就意味着内部类无法做到在没有外部类实例的情况下而直接使用,所以和我们刚写的第一条相悖。
所以在非静态内部类中不能定义静态内容【这句话不全对,我们继续往下看】
测试方案:
测试非静态内部类是否可以定义静态常量?【编译期常量】
代码用例:
测试结果:
结论:我们是可以在非静态内部类中定义静态常量的【这里要注意静态常量一定拥有一个编译期常量的】
第一:根据上面的测试用例2,我们总结的结论,继续向下推导。为什么在非静态内部类中常量是可以被static修饰的。这里要注意,num这个变量被final static修饰后,由于所赋值为字面常量,而此时字面常量会在编译阶段确定值,我们将这样的常量称之为编译期常量,而编译期常量是不需要加载类的字节码文件的,很多书上将这一步称之为编译期常量折叠【编译器在编译阶段通过语法分析计算出常量表达式的具体值】。
第二:通过上一步的理解,我们也可以这样说,编译期常量不会导致类加载,那么基于这一条,我们就可以理解为什么静态常量在非静态内部类中定义是合法的。
测试方案:
测试非静态内部类是否可以定义静态常量?【运行期常量】
代码用例:
思考:为什么用
Math.random();
就不行了呢?结论:其实这里的原因就是和测试用例2和测试用例3结合起来的。因为此时这里赋值不在时编译期常量,而是非编译期常量,对于这样的值而言编译期无法折叠编译器只能做一些语法检查,比如该常量之是否在其他地方做了修改等。。。既然无法确定值,那么就会导致该常量值的确定需要类被加载时确定,其实也和我们测试用例2一样,就会报错。
所以非静态内部类中不能拥有静态成员变量/方法,但是可以有静态的编译期常量,不能使用非编译期常量。通过这个我们也可以理解为什么有些类中定义的字符串会通过static final修饰了。无需导致类加载,在一定程度上降低了内存消耗。
版权声明:本文为原创文章,未经博主允许不责转载。
地址:https://www.jianshu.com/p/4dbe68850e1b