从局部内部类说起

先上测试代码:

public class TestCompileConstant {
public static void main(String[] args) {
List list = method2();
Field[] fields = list.getClass().getDeclaredFields();
Constructor[] cons = list.getClass().getDeclaredConstructors();
for(Constructor con:cons){
System.out.println(con.toString());
}
for(Field field:fields){
System.out.println(field.toString());
}
}
static List method2(){
Random ran = new Random();
final int a = ran.nextInt();
final int b = 5;
final int bb = ran.nextInt();
final int[] cc = new int[12];
for (int i = 0; i < cc.length; i++) {
cc = i;
}
System.out.println(a);
return new AbstractList(){
public Object get(int i){
if(i<0||i>=cc.length)
return b;
return cc[i];
}

@Override
public int size() {
switch(2){
case 1:
// case a: //is not compile-time constant
break;
}
int c = bb;
return a;
}
};
}
}



奇怪的地方:
List list = method2();
list.get(1) = 1; //???????
照理说 method2()的返回值list get()方法返回是一个本该失效的局部变量cc,那么是什么使cc能够存活下来呢?

第一天: 粗看int[] 为对象,那么应该存在heap区,当方法结束后,内部类list 中仍有应用所以没有被gc .
问题: int[] 是对象没错,那么换一个基本类型呢?局部变量b一样可以被返回怎么解释?

第二天: b 为一个compile-time constant 即编译时常量,当运行时b是作为literal存在的,即运行时代码应为: if(i<0||i>cc.length) return 5;
问题: 从这个角度似乎能解释问题了,那么运行时常量 a 又如何呢?

第三天: 从测试代码看,a也可以被正常返回,通过查阅资料理解为: jvm处理一个 .class ,将对像放入heap区;具体执行的方法在java栈的java帧中;类的基本信息存放在方法区,其中也包括常量池.故推论,final a 存入常量池,方法结束java帧销毁但与常量无关,故可以被访问.

第四天: 常量池中只有 compile-time constant , 像a这样的运行时常量不在此列,迷茫中...

第五天: 真相大白,局部内部类凡是引用外部的运行时常量,jvm都会自动为其创建一个final field,及一个相应的构造方法. 关于为什么compile-time constant 不需要,请看第二天内容.
这也说明为什么内部类中只能访问外部的final属性,它需要自己也copy一份作为自己的field,而使用final修饰符就不用担心两者的不一致.

具体可见test code 的输出内容,利用反射我们可以得到 list 的内部结构:

test.newTest.TestCompileConstant$2(int,int)
public java.lang.Object test.newTest.TestCompileConstant$2.get(int)
public int test.newTest.TestCompileConstant$2.size()
private final int test.newTest.TestCompileConstant$2.val$bb
private final int test.newTest.TestCompileConstant$2.val$a


over....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值