- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
问题
当一个内部类(注意:非静态)被实例化时,它将获得对外部类的引用(在其构造时)。关于此引用的持久性,哪些保证适用于这种情况(如果有)?
详细解释(试图让问题有意义)
考虑这个简单的代码:
public class OuterInnerExample {
private int mInt;
public void startJob() {
InnerRunnable r = new InnerRunnable();
Thread t = new Thread(r);
t.start();
}
private class InnerRunnable implements Runnable {
public void run() {
int localInt = mInt;
System.out.println(localInt);
}
}
}
编译后,如果我们反编译类文件(我使用jad
),我们可以观察到InnerRunnable
有一个this$0
成员,它是对 OuterInnerExample
对象的引用。
这个引用是在 InnerRunnable
的编译器综合构造函数中设置的,在调用 super()
之前(所以这避免了 this$0
可能是 null
当对象在其构造完成之前被使用时,即通过基类)。
当 InnerRunnable
想要访问 mInt
时,它会使用一个由编译器合成的静态 getter,它将对 OuterInnerExample
的引用作为参数(这将是 this$0
)。这个 getter 是 access$100
方法。
作为引用,可以在此处找到反编译的 Java:http://pastebin.com/gr8GB03t .
现在,整个问题是我观察到(但无法解释)类似于以下的堆栈跟踪:
FATAL EXCEPTION: main
java.lang.NullPointerException
at <package.name>.OuterInnerExample.access$100(<line where "class OuterInnerExample" is>
at <package.name>.OuterInnerExample$InnerRunnable.run(<line where "public void run()" is>)
这让我觉得 this$0
那时一定是 null
。
最佳答案
回答你的问题:作为JLS 8.1.3状态:
When an inner class (whose declaration does not occur in a static context) refers to an instance variable that is a member of a lexically enclosing class, the variable of the corresponding lexically enclosing instance is used.
阅读JLS 17.4.5关于 happens-before 关系:
The default initialization of any object happens-before any other actions (other than default-writes) of a program.
这里的默认初始化是指给字段赋默认值。
由于字段 private int mInt
是原始字段,因此它不能为 null
,因此您必须寻找其他地方。
我的猜测是您从这部分开始使用了一些自定义编译器:
private OuterInnerExample$InnerRunnable(OuterInnerExample outerinnerexample)
{
this$0 = outerinnerexample;
super();
}
导致编译时错误。您必须在构造函数的第一行调用 super()
。
我实际上复制粘贴了您的原始代码并使用 java 1.7 来执行它并且它没有问题地工作所以我们在这里缺少上下文。
关于java - Java 是否保证对外部类的引用持久化?下面的踪迹怎么可能呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20067697/
我是一名优秀的程序员,十分优秀!