10

次のケースを検討してください。

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

Eclipse の警告から引用します。Java コンパイラは合成アクセサ メソッドによってコンストラクタ AB() をエミュレートします。コンパイラーが先に進み、B 用の追加の「水中」コンストラクターを作成すると思います。

これはかなり奇妙に感じます: クラス B が A の ako フィールドとして表示されないのはなぜですか? そして: クラス B は実行時に非公開ではなくなるということですか? そして: クラス B の protected キーワードの動作が異なるのはなぜですか?

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

4 に答える 4

25

内部クラスは、基本的に Java 1.1 で導入されたハックです。JVMには実際には内部クラスの概念がないため、コンパイラーはそれを邪魔する必要があります。コンパイラは、クラス A の「外部」であるが同じパッケージ内にクラス B を生成し、合成アクセサー/コンストラクターをクラス A に追加して、A がクラス B にアクセスできるようにします。

B に保護されたコンストラクターを指定すると、合成コンストラクターを追加する必要なく、同じパッケージ内にあるため、A はそのコンストラクターにアクセスできます。

于 2009-07-06T09:58:04.900 に答える
5

この質問は現在ほぼ3年前のものですが、質問の一部がまだ回答されていないことがわかりました。

そして:それは、クラスBが実行時にプライベートではなくなったことを意味しますか?

skaffmansの回答が示唆するCarlosHeubergersのコメントによると、クラスBはまだprivateパッケージ内の他のクラス用です。

彼はおそらくJavaプログラミング言語に適しています。つまりB、他のクラスからクラスを参照することはできません。少なくともリフレクションを使用せずに(プライベートクラスのメンバーにも外部からアクセスできる)、これは別の問題です。

しかし、JVMには(skaffmanが述べているように)内部クラスの概念がないため、バイトコードレベルで「1つのクラスだけがアクセスできる」可視性がどのように実現されるかを自問しました。答え:それはまったく実現されていません。JVMの場合、内部クラスは通常のパッケージのプライベートクラスのように見えます。つまり、自分でバイトコードを作成する(またはコンパイラによって生成されたバイトコードを変更する)と、B問題なくクラスにアクセスできます。

同じパッケージ内のすべてのクラスからすべての合成アクセサーメソッドにアクセスすることもできます。Aしたがって、クラスのメソッドでクラスのプライベートフィールドに値を割り当てるBと、デフォルト(つまりパッケージプライベート)の可視性を持つ合成アクセサメソッドがクラスA(のような名前access$000)で生成され、値が設定されます。このメソッドはクラスからのみ呼び出されることになっていますB(実際、Java言語を使用してそこからのみ呼び出すことができます)。ただし、JVMの観点からは、これは他のメソッドと同様に単なるメソッドであり、任意のクラスから呼び出すことができます。

だから、質問に答えるために:

  • Java言語の観点からは、クラスBはプライベートであり、プライベートのままです。
  • JVMの観点からは、クラス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 に答える