探究为何非静态内部类不能有静态成员

首先要弄清楚非静态内部类的概念。
非静态内部类如下:

public class Outer {
class Inner {
//public static int si = 1;错误,不允许存在静态的内部成员
public static final int i = 1;
}
public static void main(String[] args) {
Outer outer = new Outer();
//错误非静态内部类的创建必须要有一个外部类的实例
//Outer.Inner inner = new Outer.Inner();
Outer.Inner inner = outer.new Inner();//正确
System.out.println(Outer.Inner.i);//正确
}
}

非静态内部类的创建、访问都需要有一个外部类的实例,通过外部类的实例才能访问到内部类。从底层的角度来说,外部类的实例持有持有指向内部类的指针,只有通过外部类实例才能访问到内部类的数据。
那么,为什么非静态内部类不能有静态的成员呢!?
首先从内存分配角度来说,众所周知,静态成员是在类加载时候分配内存空间的;但对于内部类来说,要访问它的成员,就要有一个外部类实例,但是在加载类的时候不可能实例化一个外部类给内部类的,因此,没有任何外部类的实例持有这个静态成员的指针,内部类的静态成员是无法访问到的,所以Java不允许有非静态内部类的静态成员。
有人会问,为什么不能用Outer.Inner.si来访问。很简单,如果这样就和静态内部类的静态成员的访问方式重复了,并且违反Java定义的非静态内部类要依赖外部类实例的原则。

有一种情况,就是

public static final int i = 1;

为什么加了final就可以了呢,并且是通过Outer.Inner.i的方式访问,是不是违规了。其实这里Outer.Inner.i并不是通过变量来访问的,他在编译期已经确定了值,因为编译器会对static final 声明的变量做优化,会用常量替换static final声明的变量,因此,这里用常量1去代替了这里的Outer.Inner.i。虽然final可以在static块里面初始化值,但是非静态内部类已经不允许静态成员,同时由于编译器的优化的需要和非静态内部类依赖于外部类实例的特殊性,非静态内部类的static final 只能用在基本类型(int,short,long byte,double,float, char,boolean)和字符串(String)类型上(数组也不行)。

Outer.Inner.i被替换的具体证据看class字节码[color=red]22、25、26行[/color]部分


// 堆栈:4,局部:3
public static void main(java.lang.String[] args);
0 new Outer [1]
3 dup
4 invokespecial Outer() [16]
7 astore_1 [outer]
8 new Outer$Inner [17]
11 dup
12 aload_1 [outer]
13 dup
14 invokevirtual java.lang.Object.getClass() : java.lang.Class [19]
17 pop
//这里也说明了,Inner初始化时候需要一个Outer的实例,
// 隐含的需要Outer参数的构造函数
18 invokespecial Outer$Inner(Outer) [23]
21 astore_2 [inner]
//获取输出流(控制台)
22 getstatic java.lang.System.out :java.io.PrintStream [26]
25 iconst_1//明显被编译器替换成常量了,这里意思是将常量1传入寄存器
//以寄存器中的int值作为参数,调用println方法
26 invokevirtual java.io.PrintStream.println(int) : void [32]
29 return


对为何非静态内部类不能有静态成员的问题就探究到这里,如有错误请指出。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值