我有以下java类:
class Outer
{
private Integer a;
private Long b;
class Inner
{
public void foo()
{
System.out.println("a and b are " + a + " " + b);
}
}
}
当我在Outer和Outer $ Inner上运行javap时,我得到以下内容:
C:\test>javap Outer
Compiled from "Outer.java"
class Outer extends java.lang.Object{
Outer();
static java.lang.Integer access$000(Outer);
static java.lang.Long access$100(Outer);
}
C:\test>javap Outer$Inner
Compiled from "Outer.java"
class Outer$Inner extends java.lang.Object{
final Outer this$0;
Outer$Inner(Outer);
public void foo();
}
我有两个问题:
1)为什么java编译器生成静态方法,在外层类中使用'Outer'参数来访问其私有变量?为什么不是内部类可以通过它的这个$ 0成员轻松调用的实例方法?
2)为什么内部班级的0美元成为最终?如果它不是最终会发生什么?
谢谢和问候。
答案 0 :(得分:13)
非静态内部类具有对外部类的实例的隐式引用。这是作为外部类的final
引用实现的。如果它不是final
技术上可以在实例化后修改。
隐式传递外部类,这就是为什么内部类上的任何构造函数都具有外部类的隐式参数,这就是传递this$0
的方式。
编辑,对于access$000
方法,关键线索是他们是包访问权限,他们将Outer
作为参数。因此,当Inner
中的代码调用时,例如Inner.this.a
,它实际上正在调用Inner.access$000(this$0)
。因此,这些方法可以访问外部类的private
成员到内部类。
答案 1 :(得分:2)
1)它们必须是static
,以便在某些子类中不被覆盖。我希望你明白。
<强> <Addendum>
强>
static
方法不能被覆盖的事情。覆盖在对象中是唯一的,它可以促进多态性。而静态方法属于该类。找到了一些很好的资源来支持我的论点,并让你明白静态方法不能被覆盖。
现在对于您的第二次反驳,您说他们具有包级访问权并且无法在包外的子类中重写。但我不知道为什么你忽略了同一个包中存在子类/ es的情况。它是一个有效的案例,IMO。事实上,在实际工作中命名像access$000()
之类的方法或类似的东西是荒谬的。但是不要低估意外覆盖的可能性。可能存在这样的情况:Outer
的子类,比如SubOuter
,也有自己的内部类。我自己并没有尝试javap
那个案子,只是猜测。
<强> </Addendum>
强>
2)即使您认为它不会被修改,但从技术角度来说,已经有可能已经明确指出,使用final
可以提供编译器的简单优化。