10

考虑以下情况:

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

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

我觉得这很奇怪:为什么 B 类在 A 中作为 ako 字段不可见?并且:这是否意味着 B 类在运行时不再是私有的?并且:为什么 B 类的受保护关键字的行为不同?

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

4 回答 4

25

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

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

于 2009-07-06T09:58:04.900 回答
5

我知道这个问题现在已经快三年了,但我发现部分问题仍然没有回答:

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

Carlos Heubergers 对 skaffmans 回答的评论表明,类B仍然private适用于包中的其他类。

对于 Java 编程语言,他可能是正确的,即不可能B从其他类引用类。至少不能不使用反射(也可以从外部访问私有类成员),但这是另一个问题。

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

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

所以,回答这个问题:

  • 从 Java 语言的角度来看,类B是私有的并且保持私有。
  • 从 JVM 的角度来看, class B(或更好的: class A$B)不是私有的。
于 2012-05-17T15:55:24.437 回答
2

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

public class A {
  public A() { b = new B(); }
  B b;
  private class B {
    B() { }
  }
}
于 2009-07-06T10:20:15.043 回答
-1

你需要使用

this.new B();
于 2009-07-06T09:55:43.830 回答