4

Java では、匿名クラスに新しいフィールドを持たせることができます。

class A {
   public static void main(String[] args) {
       Object o = new Object() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }
       };
       System.out.println(o.x);
   }
}

oただし、タイプが であるため、この例ではアクセスできませんObject

$ javac A.java && java A
A.java:10: cannot find symbol
symbol  : variable x
location: class java.lang.Object
       System.out.println(o.x);
                           ^
1 error

o実際には ではなく、Objectを拡張する別のクラスのインスタンスであることに注意してくださいObject。このクラスには public フィールドが 1 つありますx。このクラスに名前はありますか?にアクセスできるようにするにはどうすればo適切なタイプにすることができますo.xか? (リフレクションでこれを行うことは可能ですが、静的に行いたいことに注意してください)。

4

4 に答える 4

3

このクラスには名前があります。ですA$1。ただし、コンパイル時にこれにアクセスすることはできません (コンパイラが作成A$1します)。したがって、リフレクションなしではフィールドにアクセスできません。

Eclipse を使用している場合は、 [ソース] メニュー ( AltShiftS) → [匿名クラスをネストに変換] を使用して、自動的に「実際の」クラスに変換できます。

または、次のようにすることもできます。

class A {
   public static void main(String[] args) {
       I o = new I() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }
           public int getX() { return x; }
       };
       System.out.println(o.getX());
   }
   interface I {
       public int getX();
   }
}

編集:これは、これを達成するための本当に悪い方法であり、すべきではありません:

class A {
   public static void main(String[] args) {
       Object o = new Object() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }

           public Object clone() {
               // BAD BAD BAD
               return x;
           }
       };
       try {
           System.out.println(o.clone());
       } catch (CloneNotSupportedException cnse) {
           assert false;
       }
   }
}
于 2013-05-10T21:26:35.043 に答える
1

Java は C# ではありません。間違っていなければ、そのような構文糖衣が許可されています。sun.reflect.MagicAccessorImpl を見ることができます。しかし、このクラスは一般的な方法ではありません。自動生成コードにのみ使用されます。MagicAccessorImpl を拡張すると、JVM はフィールド アクセス レベルのチェックを実行しません。したがって、次のようなことができます。

// ----- A.java -----
class A {
    private int privateField = 5;
}

// ----- B.java -----
class B extends sun.reflect.MagicAccessorBridge {
    public static void main(String[] args) {
        A a = new A();
        a.privateField = 10;
        System.out.println(a.privateField);
    }
}

// ----- MagicAccessorBridge.java -----
package sun.reflect;

public class MagicAccessorBridge extends MagicAccessorImpl {
    // Since MagicAccessorImpl is package-private, we'll make a public bridge
}

ここから撮影

于 2013-05-15T11:04:20.720 に答える
0

このような

class A {
   public static void main(String[] args) {
       Object o = new Object() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }
       };
       //System.out.println(((A$1)o).x);
   }
}

一度コンパイルする

$ java A.java

印刷行のコメントを外す

再コンパイルして実行

$ java A.java && java A
x: 0
x: 1
2
于 2013-05-16T03:15:38.030 に答える