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。这个类有一个公共字段x。这个类有名字吗?我怎样才能o成为正确的类型,以便我可以访问o.x?(请注意,可以使用反射来做到这一点,但我想静态地做到这一点)。

4

4 回答 4

3

您可以直接在匿名类创建表达式上访问它:

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

但是,您不能再使用创建的对象,所以它有点没用。

于 2013-05-10T23:49:42.760 回答
3

这个类确实有一个名字。是A$1。但是,您无法在编译时访问它(编译器A$1为您创建)。因此,您无法在没有反射的情况下访问该字段。

如果您在 Eclipse 中,您可以使用Source菜单 ( AltShiftS) → Convert Anonymous Class to Nested自动将其转换为“真实”类。

或者,您可以:

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 回答