java内部/外部类关于外部类私有变量访问的问题

java inner/outer class questions about outer class private variables access

我有以下Java类:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Outer
{
    private Integer a;
    private Long b;

    class Inner
    {
        public void foo()
        {
            System.out.println("a and b are" + a +"" + b);
        }
    }
}

当我在外$inner和外$inner上运行javap时,我得到以下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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编译器生成在外部类中访问外部变量的静态方法来访问它的私有变量?为什么内部类可以通过它的$0成员轻松调用实例方法?

2)为什么这是0美元的内舱决赛?如果不是最终结果会怎样?

谢谢和问候。


非静态内部类具有对外部类实例的隐式引用。这是作为对外部类的final引用来实现的。如果不是final,技术上可以在实例化后修改。

外部类是隐式传递的,这就是为什么内部类上的任何构造函数都具有外部类的隐式参数的原因,这就是如何传入this$0

编辑:对于access$000方法,关键的线索是它们是包访问,它们以Outer作为参数。所以当Inner中的代码调用时,比如说Inner.this.a实际上是在调用Inner.access$000(this$0)。因此,这些方法可以让外部阶级的private成员进入内部阶级。


1)它们必须是static,以便在某些子类中不被覆盖。希望你能理解。

施里尼,从你的评论来看,似乎有必要解释这些事情以避免一些误解。首先,要知道static方法不能被重写。覆盖在对象中是排他的,它是为了促进多态性。而静态方法属于类。找到了一些很好的资源来支持我的论点,并且让您理解静态方法不能被重写。

  • 可以在Java中重写静态方法吗?
  • 为什么静态方法不能是抽象的

现在,对于您的第二个反驳,您说得对,它们具有包级别的访问权限,并且不能在包外部的子类中被重写。但我不知道为什么您忽略了子类/es存在于同一个包中的情况。这是一个有效的例子,国际海事组织。事实上,在一个真实的作品中命名一个像access$000()这样的方法是荒谬的。但不要低估意外超越的可能性。有些情况下,比如说SubOuter的子类Outer本身也有一个内部类。我自己也没试着去想那个案子,只是猜测而已。

2)即使你认为它不会被修改,技术上也有可能,正如克莱特斯已经指出的那样,使用final可以很容易地由编译器进行优化。