Java-java中匿名内部类和局部内部类中使用外部定义的对象为什么要求这个对象是final的
问题如题目所述。看了下网上的一些分析,感觉众说纷纭,理解各不相同,希望明白人给解释一下。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
问题如题目所述。看了下网上的一些分析,感觉众说纷纭,理解各不相同,希望明白人给解释一下。
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(1)
惭愧自己一直以来知其然不知其所以然, 研究了一下,做了点试验, 这个链接比较靠谱:
http://developer.51cto.com/art/200906/128214.htm
先说理论
java里是没有闭包的, 也就是说, 方法返回后, 方法里的本地变量就被释放, 不可以再被使用了. 这可以对比一下javascript里闭包的概念来理解.
那么, 这和 我们使用内部类的经验矛盾了, 因为很多时候, 外部的方法退出了, 内部类里还是可以用外部类方法里的本地变量(当然是final的)的. 为什么呢? 因为这里java实现欺骗了我们. 实际上内部类里根本就没有访问外部类的本地变量, 而是做了一份拷贝(拷贝也是final的!), 内部类里一直使用的是这个拷贝.
这样的话, 外部类的本地变量设为final就很好理解了. 否则如果可以修改, java的这个骗局就维持不住了, 我们会很容易发现, 内部类和外部类里用的是两个变量.
好了, 理论部分到这里,
下面上代码:
public class Outter {
public void test(){
final int i=100000;
final String str="ABC";
final Date date=new Date();
class Inner{
void innerTest(){
System.out.println(i);
System.out.println(str);
System.out.println(date);
}
}
}
}
我们会看到, 上述外部类的int, String和Date 本地变量, 在内部类里都会有一份final的拷贝.上内部类字节码.
请注意我加的注释部分
// Compiled from Outter.java (version 1.7 : 51.0, super bit)
class Outter$1Inner {
// Field descriptor #6 LOutter;
final synthetic Outter this$0;
// Field descriptor #8 Ljava/util/Date;
private final synthetic java.util.Date val$date; //这里是Date变量的拷贝,注意是final的!
// Method descriptor #10 (LOutter;Ljava/util/Date;)V
// Stack: 2, Locals: 3
Outter$1Inner(Outter arg0, java.util.Date arg1); // 内部类的构造函数, 注意把外部类Date本地变量作为参数传入!
0 aload_0 [this]
1 aload_1 [arg0]
2 putfield Outter$1Inner.this$0 : Outter [12]
5 aload_0 [this]
6 aload_2 [arg1]
7 putfield Outter$1Inner.val$date : java.util.Date [14] //这里完成Date变量的复制
10 aload_0 [this]
11 invokespecial java.lang.Object() [16]
14 return
Line numbers:
[pc: 0, line: 8]
Local variable table:
[pc: 0, pc: 15] local: this index: 0 type: new Outter(){}
// Method descriptor #18 ()V
// Stack: 2, Locals: 1
void innerTest();
0 getstatic java.lang.System.out : java.io.PrintStream [24]
3 ldc <Integer 100000> [30] // 这里是int型的拷贝!
5 invokevirtual java.io.PrintStream.println(int) : void [31]
8 getstatic java.lang.System.out : java.io.PrintStream [24]
11 ldc <String "ABC"> [37] // 这里是String型的拷贝!
13 invokevirtual java.io.PrintStream.println(java.lang.String) : void [39]
16 getstatic java.lang.System.out : java.io.PrintStream [24]
19 aload_0 [this]
20 getfield Outter$1Inner.val$date : java.util.Date [14]
23 invokevirtual java.io.PrintStream.println(java.lang.Object) : void [42]
26 return
Line numbers:
[pc: 0, line: 10]
[pc: 8, line: 11]
[pc: 16, line: 12]
[pc: 26, line: 13]
Local variable table:
[pc: 0, pc: 27] local: this index: 0 type: new Outter(){}
Inner classes:
[inner class info: #1 Outter$1Inner, outer class info: #0
inner name: #53 Inner, accessflags: 0 default]
Enclosing Method: #48 #50 Outter.test()V
}