java内部/外部类关于外部类私有变量访问的问题
我有以下java类:java内部/外部类关于外部类私有变量访问的问题,java,class,inner-classes,decompiling,Java,Class,Inner Classes,Decompiling,我有以下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:
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) 为什么这门课的0美元是最终的?如果不是最终结果会怎样
感谢和问候。非静态内部类有一个对外部类实例的隐式引用。这是对外部类的
最终引用。如果它不是最终版
,则在实例化后可以对其进行修改
外部类是隐式传入的,这就是内部类上的任何构造函数都有外部类的隐式参数的原因,这就是这个$0
是如何传入的
Edit:至于access$000
方法,关键线索是它们是包访问,并且它们将外部
作为参数。所以当internal
中的代码调用时,比如说,internal.this.a
它实际上在调用internal.access$000(this$0)
。因此,这些方法将外部类的private
成员的访问权授予内部类。1)它们必须是静态的
,以便在某些子类中不被重写。我希望你能理解
现在,对于您的第二个反驳,您说得对,它们具有包级访问权限,不能在包外的子类中重写。但是我不知道为什么您忽略了子类在同一个包中存在的情况。事实上,在实际工作中,命名像access$000()
之类的方法是荒谬的。但不要低估意外超越的机会。有一种情况是,Outer
的子类,比如说SubOuter
,也有自己的内部类。我自己并没有尝试javap
那个案例,只是猜测而已
2) 即使您认为它不会被修改,从技术上讲,正如克莱特斯已经指出的那样,使用final
可以让编译器轻松地进行优化。为什么access$…()
方法必须是静态的?你提供的答案是针对第二个问题,也是针对从未被问过的问题。嗨,克莱特斯,谢谢你的回答。我知道“access*”方法是为了让内部类可以访问外部类的私有成员而提供的。但为什么这些方法是静态的?为什么它们不能成为实例方法?因为内部类有这个$0,所以那里的代码可以很容易地调用这个$0.access$000,如果它是一个实例方法,而不是调用Outer.access$000(这个$0)。如果它们不是静态的,那么您就必须担心每个潜在的子类会意外地重写它们。只有静态方法提供所需的特定于类的语义。。。我应该向下滚动。这让我指向了正确的方向。Lombok@Builder生成的代码在反编译时显示为returnnewerrorvo(errorCode$set?errorCode:ErrorVO.access$000())。在本例中,访问$000引用私有静态方法$default$errorCode()。Lombok似乎为每个标记的变量创建了其中一个变量。这里的例子说明了这个机制(添加在Java1.1中)是一个错误。我试图通过使用默认(包)访问权限声明a
和b
来避免这种混乱。你不会损失任何东西,因为编译器黑客使字段包可见。嗨,醋,谢谢你的回答。但是子类可以覆盖父类的静态方法;另外,在这个特定的情况下,方法是包访问,所以这个包之外的子类无论如何都不能重写它们。所以我不明白你的回答。@shrini1000:不,你在做蠢事。见我的附录。嗨,醋,谢谢你的解释。我已经编写了一个超级/子类,并对其进行了测试,然后才做出我先前的回答;但我没有考虑过超类ref指向子类对象的情况。谢谢你指出这一点。如果我的回答冒犯了你,我向你道歉;这从来不是我们的初衷。不幸的是,问题1仍然没有得到回答。非虚拟成员函数(即java术语中的final方法)与静态或独立函数之间没有技术区别:编译器确切地知道要跳转到的最终代码。派生类无法改变这一点。我更倾向于猜测编译器编写人员只是认为OO符号在这些实现细节中无关紧要,而且使用独立的access$xxx函数看起来越自然,越接近裸机编程。