Java内部可见性难题

时间:2009-07-06 09:48:14

标签: java inner-classes

考虑以下情况:

public class A {
  public A() { b = new B(); }
  B b;
  private class B { }
}

从Eclipse中的警告我引用:java complier通过合成访问器方法模拟构造函数A.B()。我想编译器现在继续为B创建一个额外的“水下”构造函数。

我觉得这很奇怪:为什么B级不会被视为a.k.o. A中的字段? 并且:这是否意味着B类在运行时不再是私有的? 并且:为什么B类的受保护关键字表现不同?

public class A {
  public A() { b = new B(); }
  B b;
  protected class B { }
}

4 个答案:

答案 0 :(得分:25)

内部类本质上是Java 1.1中引入的一个hack。 JVM实际上没有内部类的任何概念,因此编译器必须提供它。编译器在类A的“外部”生成类B,但是在同一个包中,然后向其添加合成访问器/构造函数以允许A访问它。

当你给B一个受保护的构造函数时,A可以访问该构造函数,因为它在同一个包中,而不需要添加合成构造函数。

答案 1 :(得分:4)

我知道这个问题现在已经快三年了,但我发现问题的一部分仍未得到解答:

  

并且:这是否意味着B类在运行时不再是私有的?

Carlos Heubergers对skaffmans的回答表明,对于其他课程,课程B仍然是private

他可能适合Java编程语言,即无法从其他类引用类B。至少没有使用反射(也可以从外部访问私有类成员),但这是另一个问题。

但是由于JVM没有任何内部类的概念(如skaffman所述),我问自己在字节码级别如何实现“只能通过一个类访问”的可见性。答案:它根本没有实现,对于JVM,内部类看起来像普通的包私有类。这是,如果您自己编写字节码(或修改编译器生成的字节码),您可以毫无问题地访问类B

您也可以从同一个包中的所有类访问所有合成访问器方法。因此,如果在类A的方法中为类B的私有字段分配值,则会在类A中生成具有默认(即包私有)可见性的合成访问器方法(命名类似于access$000),为您设置值。应该只从类B调用此方法(实际上它只能使用Java语言从那里调用)。但是从JVM的角度来看,这只是一种方法,可以被任何类调用。

所以,回答这个问题:

  • 从Java语言的角度来看,类B是并且保持私密。
  • 从JVM的角度来看,类B(或更好:类A$B)不是私有的。

答案 2 :(得分:2)

class B及其构造函数的访问权限不必相同。你可以拥有一个带有包范围构造函数的私有内部类,这就是我通常所做的。

public class A {
  public A() { b = new B(); }
  B b;
  private class B {
    B() { }
  }
}

答案 3 :(得分:-1)

您需要使用

this.new B();