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:

我有以下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) 为什么这门课的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函数看起来越自然,越接近裸机编程。