局部内部类是定义在方法体或代码块中的类, 在 笔记 19 中已有过简单介绍.
今天要讨论的是局部内部类为什么只能访问为常量的局部变量.
作者: 博客园 -- 蝉蝉
请尊重作者劳动成果, 转载请在标题注明 "转载" 字样, 并标明原文链接:
http://www.cnblogs.com/chanchan/p/8402411.html
参考资料:
http://www.cnblogs.com/dolphin0520/p/3811445.html 1. 首先来了解一下局部内部类是如何访问局部变量的
Person 类是外部类, LoInClassIntf 是接口, localInClassRe 是 Person 类的成员方法, 且返回值类型为 LoInClassIntf;
方法内定义了一个局部内部类 LoInnerClass, 该内部类实现了接口 LoInClassIntf;
方法内还定义了一个 final 的局部变量 a, 定义了一个 LoInnerClass 类型的对象引用 loInC;
代码如下:
// 笔记 23: 内部类 -- 局部内部类 -- 实现接口, 返回内部类对象
// 接口
public interface LoInClassIntf {void test();
}
// 方法 localInClassRe, 返回值为 LoInClassIntf, 局部内部类来实现该接口, 向上转型
public LoInClassIntf localInClassRe() {
final int a = 1; // 常量
// 笔记 23-- 内部类 -- 局部内部类 -- 实现接口
class LoInnerClass implements LoInClassIntf {
public void test() {
System.out.println("variable a:" + a);
}
}
LoInnerClass loInC = new LoInnerClass();
return loInC;
}
public static void main(String[] args) {
// 笔记 23-- 局部内部类
Person per = new Person();
LoInClassIntf lInCIntf = per.localInClassRe();
lInCIntf.test();
}
输出结果为:
1
variable a:1
成员方法 localInClassRe 执行中的内存示意图如下:
成员方法 localInClassRe 执行后的内存示意图如下:
分析:
成员方法 localInClassRe 执行后, 方法体中的局部变量 a 和对象引用 loInC 都被释放掉了, 但分配在堆中的对象未回收, 这时由 main 方法中的局部变量 lInCIntf 来指向它;
到这里还没什么问题, 但第 27 行, lInCIntf 调用了 test 方法, test 方法中访问到了成员方法 localInClassRe 中的局部变量 a, 而 a 此时已不存在了, 所以就会出现错误;
即, 局部变量与局部内部类的对象的生命周期不同;
为解决这一问题, Java 把局部内部类要访问的局部变量重新拷贝了一份, 并把备份放在内部类的常量池中, 这样不论方法有没有执行结束, 拷贝都是存在的, 就不会再出现访问不存在的变量的错误了.
成员方法 localInClassRe 执行中的内存示意图如下:
成员方法 localInClassRe 执行后的内存示意图如下:
上面涉及到的局部变量 a 是方法体内定义的, 如果局部内部类访问的是方法体的参数呢?
Java 采取的方法是, 默认为局部内部类的构造方法传入该参数作为构造方法的参数, 然后用该参数来初始化内部类中拷贝的变量 a.
局部内部类如何访问局部变量的问题解决了, 那么为什么只能访问 final 的局部变量呢?
2. 数据同步的问题
上面通过拷贝一份局部变量来解决生命周期不同的问题, 如果方法体和局部内部类都改变了 a 的值会怎么样呢?
如下图所示:
这样两个 a 不一致, 就会出现数据不同步, 下一步应该用 a=2 还是 a=3 呢?
为解决这个问题, Java 规定局部内部类可访问的局部变量必须为 final 的, 即内部类不能改变要访问的局部变量的值, 这样就不会出现数据不同步的问题了.
来源: http://www.bubuko.com/infodetail-2484018.html