如何在没有反射的情况下访问匿名对象内声明的字段?

时间:2013-05-10 21:23:31

标签: java types inner-classes anonymous-class

可以使匿名类在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? (请注意it's possible to do this with reflection,但我想静态地执行此操作。)

4 个答案:

答案 0 :(得分:3)

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

如果您在Eclipse中,可以使用来源菜单( Alt Shift S )→< strong>将匿名类转换为嵌套以自动将其转换为“真实”类。

或者,您可以:

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;
       }
   }
}

答案 1 :(得分: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);
   }
}

但是,你不能再使用创建的对象了,所以它有点无用。

答案 2 :(得分: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
}

Taken from here

答案 3 :(得分: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

取消注释打印行

重新编译&amp;运行

$ java A.java && java A
x: 0
x: 1
2