java内部/外部类关于外部类私有变量访问的问题
我有以下 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”参数的静态方法访问其私有变量?为什么内部类不可以通过其 this$0 成员轻松调用实例方法?
2)为什么内部类中的 this$0 被定为最终的?如果不是最终结果会怎样?
谢谢和问候。
I have the following java class:
class Outer
{
private Integer a;
private Long b;
class Inner
{
public void foo()
{
System.out.println("a and b are " + a + " " + b);
}
}
}
when I run javap on Outer and Outer$Inner, I get the following:
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();
}
I have two questions:
1) why does java compiler generate static methods that take 'Outer' param, in the outer class, for accessing its private variables ? why not instance methods that the inner class can easily call through its this$0 member ?
2) why is this$0 in inner class made final ? what will happen if it is not final ?
Thanks and regards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
非静态内部类具有对外部类实例的隐式引用。这是作为对外部类的
final
引用来实现的。如果它在技术上不是final
,那么它可以在实例化后进行修改。外部类是隐式传入的,这就是为什么内部类上的任何构造函数都有一个外部类的隐式参数,这就是
this$0
的传入方式。编辑:至于
access$000
方法,关键线索是它们是包访问,并且它们采用Outer
作为参数。因此,当Inner
中的代码调用Inner.this.a
时,它实际上是在调用Inner.access$000(this$0)
。因此,这些方法的作用是让内部类能够访问外部类的私有成员。Non-static inner classes have an implicit reference to an instance of the outer class. This is implemented as a
final
reference to the outer class. If it wasn'tfinal
technically it could be modified after instantiation.The outer class is implicitly passed in which is why any constructors on the inner class have an implicit parameter of the outer class, which is how
this$0
is passed in.Edit: as for the
access$000
methods the key clue is that they're package access and they take anOuter
as an argument. So when code inInner
calls, say,Inner.this.a
it's actually callingInner.access$000(this$0)
. So those methods are there to give access toprivate
members of the outer class to the inner class.1)它们必须是
static
,以便在某些子类中不被覆盖。我希望你能理解。<附录>
Shrini,从你的评论来看,似乎有必要解释一下以避免一些误解。首先,要知道
静态
方法不能被重写。重写在对象中是独占的,它的存在是为了促进多态性。而静态方法属于类。找到了一些很好的资源来支持我的论点,并让您了解静态方法不能被覆盖。现在你的第二个反驳,你说得对,它们具有包级别的访问权限,并且不能在包外部的子类中被覆盖。但我不知道你为什么忽略子类存在于同一个包中的情况。 IMO,这是一个有效的案例。事实上,在实际工作中,将方法命名为
access$000()
或类似的名称是荒谬的。但不要低估意外覆盖的可能性。可能存在这样的情况:Outer
的子类(例如SubOuter
)也有其自身的内部类。我自己并没有尝试javap
这种情况,只是猜测。2) 即使您认为它不会被修改,从技术上讲,正如 cletus 已经指出的那样,有可能使用
final 可以通过编译器提供简单的优化。
1) They have to be
static
, in order to not be overridden in some sub class. I hope you understand.<Addendum>
Shrini, from your comment, it seems that there is a need to explain the things to avoid some misconceptions. First of all, know on thing that
static
methods can not be overridden. Overriding is exclusive in objects, and it is there to facilitate polymorphism. Whereas static methods belongs to the class. Found a couple of good resources to support my argument and for you to understand that static methods can not be overridden.Now for your second retort, you are right in saying that they have package level access and can't be overridden in subclasses outside the package. But I don't know why are you neglecting the case where subclass/es exist in the same package. Its a valid case, IMO. In fact, it would be absurd to name a method like
access$000()
or something like that, in a real work. But don't underestimate the chance of accidental overriding. There can be a case where the subclass ofOuter
, saySubOuter
, has an inner class of itself too. I didn't try tojavap
that case myself, just guessing.</Addendum>
2) Even if you think it will not get modified, technically there is a possibility as cletus pointed out already, use of
final
can provide easy optimizations by the compiler.