2

Java でラムダ式を実行する方法を学ぶために検索しましたが、代わりに混乱が生じました。したがって、匿名クラスに関する私の理解は次のとおりです。

public class SomeObject {
   public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add(new SomeObject());
   }

}

匿名内部クラスという言葉は以前に見たことがありますが、その時は通常の匿名クラスが何であるかを知りませんでした。私が見ているスレッドやビデオの多くは、匿名の内部クラスを単に「匿名クラス」と呼んでいるようです。それらは同義ですか?匿名内部クラスの私の理解は次のとおりです。

 public class Rectangle {
 private double length;
 private double width;
 private double perimeter;

    public void calculatePerimeter() {
    perimeter = (2*length) +(2*width);
   }

     public static void main(String[] args) {
       Rectangle square = new Rectangle() {
        public void calculatePerimeter() {
            perimeter = 4*length;
        }
    };
   }

  }

基本的に、Square のサブクラスを作成してから calculatePerimeter() メソッドをオーバーライドする代わりに、1 回限りの Square クラスを作成し、それらのメソッドをオーバーライドすることができます。これは正しいです?

したがって、匿名の内部クラスは継承と関係があります。私はそれの使用を理解していません。おそらく、これまでにそれらを使用したことがないか、プログラミングの経験があまりないためです。例を挙げたり、それが役立つ場合に説明したりできますか?

更新: 匿名内部クラスのコードを IDE に移動したときに、エラーがあることがわかりました。どうやら、「正方形」は長方形のフィールドを継承していません。これでますます駄目になりませんか?

同等のものは次のとおりです。

public class Rectangle {
 private double length;
 private double width;
 private double perimeter;

    public void calculatePerimeter() {
    perimeter = (2*length) +(2*width);
   }
 }


public class Square extends Rectangle {
   @Override   
   public void calculatePerimeter() {
      perimeter = 4*getLength();
   }

  public double getLength() {
    return length;
  }



    }
4

3 に答える 3

6

したがって、匿名クラスに関する私の理解は次のとおりです。

public class SomeObject {
   public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add(new SomeObject());
   }
}

匿名クラスはありません。クラスSomeObjectには名前があります...したがって、匿名ではありません。実際、これは通常の (ネストされておらず、内部でなく、匿名ではない) Java クラスです。


匿名内部クラスという言葉は以前に見たことがありますが、その時は通常の匿名クラスが何であるかを知りませんでした。

「通常の匿名クラス」などというものはありません。すべての Java 匿名クラスは「内部」です。

JLSが言うように:

「内部クラスは、明示的または暗黙的に静的に宣言されていないネストされたクラスです。

内部クラスには、ローカル (§14.3)、匿名 (§15.9.5)、および非静的メンバー クラス (§8.5) が含まれます。


したがって、匿名の内部クラスは継承と関係があります。

匿名の内部クラスには継承含まれますが、それがそれらを「内部」にするものではありません。上記を参照。


私は「list.add(私は「list.add(new SomeObject());」を意味した.);". この間ずっと、あなたが ArrayList に追加したオブジェクトは名前を付けていなかったので匿名クラスと呼ばれていたと思いました。

あなたは間違っています。オブジェクトはクラス1ではありません。

クラスではnew SomeObject()なく、オブジェクトを作成しています。しかし、それはごく普通のことです。オブジェクト/インスタンスには名前がありません... JLSに関する限り。

変数とフィールドには名前が付けられましたが、変数はオブジェクト/インスタンスまたはクラスではありません。これらは、オブジェクトへの参照を保持できる名前とスロットの間のバインディングです (それが型宣言で許可されている場合)。

java.lang.Class1 - ...のインスタンスの場合を除き、理論的な観点からは、オブジェクトは実際にはクラス/タイプではありません。


それとも、単に匿名オブジェクトと呼ばれ、2 つが混同されていたのでしょうか。

いいえ。オブジェクトには名前がありません。すべての Java オブジェクトは「匿名」です。区別するのは有用ではありません。(そして、変数について話している上記を参照してください...)


Rectangle/の例についてSquareは、匿名クラス、内部クラス、ネストされたクラスなどとは何の関係もありません。これらは、通常の Java 継承を使用する単なるトップレベル クラスです。(別の「非通常」の種類の継承があることを示唆しているわけではありません...)

于 2014-03-29T01:44:01.817 に答える
1

後のコメントに答えると、「新しいサブクラスを作成すると、それらのプライベート インスタンス変数が継承されます。匿名内部クラスの場合は継承されませんでした。」

サブクラスprivateがスーパークラスのフィールドを「継承」することはありません (JLS 用語を使用)。ただし、サブクラスは、配置されている場所に応じて、これらのプライベート フィールドを参照できる場合があります。サブクラスがスーパークラス内で宣言されている場合、または両方が同じ最上位クラス内にネストされている場合、サブクラスのメソッドは引き続きフィールドにアクセスできます。C.javaクラスが 1 つだけのソース ファイルがあると仮定すると、 のどこかで宣言されたフィールドはC、の他のほとんどの場所から引き続きアクセスできます。privateC.javaC.java

ただし、これをテストすると、いくつかの興味深いニュアンスが見つかりました。

class Foo1 {    
    private int bar1;
    public static class Foo2 extends Foo1 {
        public void p() {
            System.out.println(bar1);               // illegal
            System.out.println(((Foo1)this).bar1);  // works
        }
    }
}

bar1スーパークラスのプライベート フィールドですが、表示されます。継承されませんが、コンパイラにFoo2オブジェクトをFoo1. しかしbar1、それ自体を参照するだけでは失敗します。Java はこれを(スーパークラスではなく)囲んでいるインスタンスbar1のを取得しようとしていると解釈しますが、静的であるため、囲んでいるインスタンスはありません。Foo2

が外部Foo2で宣言されている場合、2 番目は非公開であるため、今はまったく表示されないため、不正になることに注意してください。ここでの教訓は、「継承」と「可視性」(または「アクセス」) は同じものではないということです。同じことが匿名の内部クラスにも当てはまります。プライベート インスタンス フィールドが表示される場所で使用すると、そのフィールドを参照できます。プライベート インスタンス フィールドが表示されない場所で使用すると、使用できません。この目的のためには、クラス宣言の場所が、クラスのタイプ (ネスト/内部/匿名) よりも重要です。 Foo1printlnbar1

キーワードを取り除き、staticそれを内部クラスにするとします。

public class Foo1 {

    private int bar1;

    public Foo1(int x) {
        bar1 = x;
    }

    public class Foo2 extends Foo1 {

        public Foo2(int x) {
            super(x * 10);
        }

        public void show() {
            System.out.println("bar1 = " + bar1);
            System.out.println("((Foo1)this).bar1 = " + ((Foo1)this).bar1);
            System.out.println("Foo1.this.bar1 = " + Foo1.this.bar1);
        }
    }
}

public class Test64 {

    public static void main(String[] args) {
        Foo1 f1 = new Foo1(5);
        Foo1.Foo2 f2 = f1.new Foo2(6);
        f2.show();
    }

}    

Foo2オブジェクトもFoo1;になりました。しかし、それは内部クラスであるため、インスタンスにはのオブジェクトである囲みインスタンスFoo2もあります。を作成すると、スーパークラス コンストラクターを使用してスーパークラスを 60 に設定します。ただし、 5 である囲みインスタンスも持っています。次の出力が表示されます。 Foo1Foo2bar1bar1show()

bar1 = 5
((Foo1)this).bar1 = 60
Foo1.this.bar1 = 5

したがってbar1、それ自体で、囲んでいるインスタンスのフィールドを参照します。

于 2014-03-30T02:00:11.733 に答える