28

これら 2 つの内部クラス宣言の違いは何ですか? また、長所/短所についてコメントしますか?

ケース A: クラス内のクラス。

public class Levels {   
  static public class Items {
    public String value;
    public String path;

    public String getValue() {
      return value;}
  }
}

ケース B: インターフェイス内のクラス。

public interface Levels{

  public class Items {
    public String value;
    public String path;

    public String getValue() {
      return value;}
  }
}

修正: getvalue メソッドの配置。

詳細情報: インターフェイス AT ALL を実装していない別のクラスで、ケース A と B の両方で Items クラスをインスタンス化できます。

public class Z{//NOTE: NO INTERFACE IMPLEMENTED here!!!!
 Levels.Items items = new Levels.Items();
}

インターフェースはインスタンス化されていないため、インターフェースをインスタンス化できないという理由だけでインスタンス化された LEVELS インターフェースなしで、インターフェース内のすべての要素にドット表記でアクセスできます。事実上、インターフェース内で定義されたクラスを静的参照に対して透過的にします。

したがって、 B が静的でない場合の Items クラスと言っても意味がありません。A と B の両方のケースが同じ方法でインスタンス化されるため、静的、内部、またはネストされたものに関するセマンティクスを探しているわけではありません。セマンティクスに関する回答はやめてください。コンパイラ、ランタイム、および動作の違い/利点が必要です。ない場合は、そう言います。セマンティクスに関するこれ以上の回答はありません!!!!! JVM または .NET VM 仕様内部の専門家は、教科書の意味論者ではなく、この質問に答えてください。

4

6 に答える 6

27

内部クラスはネストされたstaticクラスであり、非静的は内部クラスと呼ばれます。詳細については、こちらをご覧ください

ただし、同じリンクからの抜粋を引用したいと思います。

入れ子になった静的クラスは、他の最上位クラスと同様に、その外側のクラス (および他のクラス) のインスタンス メンバーと対話します。実際には、入れ子になった静的クラスは、パッケージ化の便宜のために別のトップレベル クラスにネストされたトップレベル クラスの動作です。

static2 番目のケースではその単語を使用しませんでした。そして、あなたはそれがstaticインターフェースであるため、暗黙のうちにそうなると思います。あなたはそれを仮定して正しいです。

実際にはネストされたクラスであるため、静的なネストされたクラスと同じように、インターフェイスで内部クラスをインスタンス化できますstatic

Levels.Items hello = new Levels.Items();

したがって、上記のステートメントは両方のケースで有効になります。最初のケースは静的なネストされたクラスであり、2 番目のケースでは を指定しませんでしstaticたが、それでもインターフェイスにあるため、静的なネストされたクラスになります。したがって、一方がクラスにネストされ、もう一方がインターフェイスにネストされているという事実以外に違いはありません

通常、 interface ではなくクラス内の内部クラスは、次のようにインスタンス化されます。

Levels levels = new Levels();
Levels.Items items = levels.new Items();

さらに、「非静的」内部クラスは、その外部クラスへの暗黙的な参照を持ちます。これは、「静的な」ネストされたクラスには当てはまりません。

于 2009-12-04T09:07:18.613 に答える
15

静的内部クラスは、内部クラスがそれを囲むクラスのすべての静的変数とメソッドにアクセスできることを除いて、ほとんどトップレベルのクラスに似ています。囲んでいるクラス名は、内部クラスのパッケージ名前空間に効果的に追加されます。クラスを静的内部クラスとして宣言することにより、クラスがそれを囲むクラスのコンテキストに何らかの形で不可分に結び付けられていることを伝えています。

非静的内部クラスはあまり一般的ではありません。主な違いは、非静的内部クラスのインスタンスには、それを囲むクラスのインスタンスへの暗黙の参照が含まれ、その結果、その包含クラスインスタンスのインスタンス変数とメソッドにアクセスできることです。これにより、次のような奇妙なインスタンス化イディオムが発生します。

Levels levels = new Levels(); // first need an instance of the enclosing class

// The items object contains an implicit reference to the levels object
Levels.Items items  = levels.new Items(); 

非静的内部クラスは、静的内部クラスよりも、それらを囲むクラスにはるかに密接に関連付けられています。それらには有効な用途があります(たとえば、イテレータは、反復するデータ構造のクラス内の非静的内部クラスとして実装されることがよくあります)。

静的内部クラスの動作のみが本当に必要な場合に、非静的内部クラスを宣言するのはよくある間違いです。

于 2009-12-04T09:39:55.307 に答える
15

インターフェイスでネストされたクラスを宣言すると、それは常にpublicおよびstaticになります。そう:

public interface Levels{
    class Items {
        public String value;
        public String path;

        public String getValue() {return value;}
    }
}

とまったく同じです

public interface Levels{
    public static class Items {
        public String value;
        public String path;

        public String getValue() {return value;}
    }
}

さらには

public interface Levels{
    static class Items {
        public String value;
        public String path;

        public String getValue() {return value;}
    }
}

これを javap -verbose で確認したところ、すべて生成されます

Compiled from "Levels.java"
public class Levels$Items extends java.lang.Object
  SourceFile: "Levels.java"
  InnerClass: 
   public #14= #3 of #23; //Items=class Levels$Items of class Levels
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method   #4.#21; //  java/lang/Object."<init>":()V
const #2 = Field    #3.#22; //  Levels$Items.value:Ljava/lang/String;
const #3 = class    #24;    //  Levels$Items
const #4 = class    #25;    //  java/lang/Object
const #5 = Asciz    value;
const #6 = Asciz    Ljava/lang/String;;
const #7 = Asciz    path;
const #8 = Asciz    <init>;
const #9 = Asciz    ()V;
const #10 = Asciz   Code;
const #11 = Asciz   LineNumberTable;
const #12 = Asciz   LocalVariableTable;
const #13 = Asciz   this;
const #14 = Asciz   Items;
const #15 = Asciz   InnerClasses;
const #16 = Asciz   LLevels$Items;;
const #17 = Asciz   getValue;
const #18 = Asciz   ()Ljava/lang/String;;
const #19 = Asciz   SourceFile;
const #20 = Asciz   Levels.java;
const #21 = NameAndType #8:#9;//  "<init>":()V
const #22 = NameAndType #5:#6;//  value:Ljava/lang/String;
const #23 = class   #26;    //  Levels
const #24 = Asciz   Levels$Items;
const #25 = Asciz   java/lang/Object;
const #26 = Asciz   Levels;

{
public java.lang.String value;

public java.lang.String path;

public Levels$Items();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable: 
   line 2: 0

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      5      0    this       LLevels$Items;


public java.lang.String getValue();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   getfield    #2; //Field value:Ljava/lang/String;
   4:   areturn
  LineNumberTable: 
   line 7: 0

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      5      0    this       LLevels$Items;


}
于 2012-04-02T13:02:41.090 に答える
7

ネストされた/内部クラスの例は(IMO)悪い例です。2番目の例は、インターフェースが(暗黙的に)抽象メソッドしか宣言できないため、有効なJavaではありません。より良い例を次に示します。

public interface Worker {

    public class Response {
        private final Status status;
        private final String message;
        public Response(Status status, String message) {
            this.status = status; this.message = message;
        }
        public Status getStatus() { return status; }
        public String getMessage() { return message; }
    }

    ...

    public Response doSomeOperation(...);
}

Responseクラスを埋め込むことで、それが他の用途のないワーカーAPIの基本的な部分であることを示しています。

Map.Entryクラスは、このイディオムのよく知られた例です。

于 2009-12-04T09:40:23.547 に答える
0

私見、利点は、プロジェクトフォルダーが些細な場合に乱雑になるクラスが少なくなることです。欠点は、要件の変更に伴って内部クラスが成長すると、メンテナンスが悪夢になることです。

于 2009-12-04T09:10:48.837 に答える
0

最初のものは Levels クラスと Items という static 内部クラスを宣言するものだと思っていました。アイテムは Levels.Items によって参照でき、静的になります。

2 つ目は、次のように、Levels.Items を使用してアクセスできる単純な内部クラスを宣言します。

Levels.Items hello = new Levels.Items();

編集: これは完全に間違っています。コメントやその他の返信を読んでください。

于 2009-12-04T09:13:57.790 に答える