[英]Why does referencing an anonymous inner class by its name work when it's a member, but not a variable?
Sorry for the title gore, I did not know how to describe the problem in one line. 对不起标题血,我不知道如何在一行中描述问题。 If you have suggestions, I'm open.
如果你有建议,我会公开的。
Suppose you have the following class: 假设您有以下课程:
public class SomeClass {
// doesn't even need to be final, which is freaky
Runnable memberRunnable = new Runnable() {
public void run() {
SomeOtherClass.someMethod(memberRunnable); // this works
}
}
public void someMethod() {
final Runnable varRunnable = new Runnable() {
public void run() {
SomeOtherClass.someMethod(varRunnable); // compiler error - "varRunnable" might not have been initialized
}
}
}
}
Why is the memberRunnable
able to access itself from inside run()
, while varRunnable
is not? 为什么
memberRunnable
能够从run()
内部访问自己,而varRunnable
不是? AFAICS it's the exact same construct. AFAICS它是完全相同的结构。
You can obviously use this
instead, I know. 我知道,显然你可以使用
this
。 I'm just wondering why the compiler makes a difference between the two cases, which seem identical. 我只是想知道为什么编译器会在两种情况之间产生差异,这两种情况看起来完全相同。 Also why it thinks
varRunnable
might not have been initialized, when it's obvious that it is at that point. 也是为什么它认为
varRunnable
可能没有被初始化,当它显然是在那时。
One could argue that, if Runnable
was a class (it's an interface), it's constructor might be trying to call run()
, thus actually running into a scenario where the reference is uninitialized. 有人可能会说,如果
Runnable
是一个类(它是一个接口),它的构造函数可能会尝试调用run()
,因此实际上会遇到引用未初始化的场景。 However, this should also be the case for memberRunnable
, but that case works. 但是,这也应该是
memberRunnable
的情况,但是这种情况有效。
Funny thing, nothing changes if instead of Runnable
you use a class, in which case the above scenario (constructor calling an overridden method) can actually happen. 有趣的是,如果使用类而不是
Runnable
,则没有任何变化,在这种情况下,上面的场景(构造函数调用重写方法)实际上可能发生。 This means that, in that case, you can run into a "field not initialized" at runtime (haven't tried it though), which is rather dumb since the compiler should guard against that. 这意味着,在这种情况下,您可以在运行时遇到“未初始化的字段”(虽然没有尝试过),这是相当愚蠢的,因为编译器应该防范它。
Also why it thinks
varRunnable
might not have been initialized, when it's obvious that it is at that point.也是为什么它认为
varRunnable
可能没有被初始化,当它显然是在那时。
No, the variable is not (in the general case) guaranteed to be initialized at that point. 不,该变量不是(在一般情况下)保证在该点初始化。
Suppose, just for the sake of argument, that Runnable
was an abstract class (rather than an interface) and that the constructor of Runnable
called this.run()
. 假设,仅仅为了参数,
Runnable
是一个抽象类(而不是一个接口), Runnable
的构造函数叫做this.run()
。 Since construction of the Runnable
occurs before the assignment, this would result in access of varRunnable
before the assignment had occurred. 由于
Runnable
构造发生在赋值之前,这将导致在赋值发生之前访问varRunnable
。
In other words, it would lead to access of an uninitialized local variable. 换句话说,它将导致访问未初始化的局部变量。 Note that this is worse than accessing a field that has not yet been explicitly initialized, since local variables are not initialized to default values.
请注意,这比访问尚未显式初始化的字段更糟糕,因为局部变量未初始化为默认值。 It's so much worse in fact, that access of uninitialized local variables is forbidden, while access to fields that have not been explicitly initialized is allowed, as you just discovered.
事实上更糟糕的是,禁止访问未初始化的局部变量,而允许访问尚未显式初始化的字段,正如您刚刚发现的那样。 (Making the field final doesn't change this. Final fields also have default values, and they can in fact change (once) in the constructor.)
(使字段最终不会改变这一点。最终字段也有默认值,它们实际上可以在构造函数中更改(一次)。)
Source: I'm a javac developer. 资料来源:我是一名javac开发人员。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.