Domanda

It's possible to make anonymous classes have new fields in 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);
   }
}

But they can't be accessed in this example, because o is of type 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

Note that o is actually not an Object, it's an instance of a different class extending Object. This class has one public field x. Does this class have a name? How can I make o be the proper type so I can get access to o.x? (Note that it's possible to do this with reflection, but I want to do it statically).

È stato utile?

Soluzione 4

like this

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

compile once

$ java A.java

uncomment print line

recompile & run

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

Altri suggerimenti

This class does have a name. It's A$1. However, you can't access this at compile time (the compiler creates A$1 for you). Thus, you can't access the field without reflection.

If you're in Eclipse, you can use Source menu (AltShiftS) → Convert Anonymous Class to Nested to convert it to a "real" class automatically.

Alternatively, you could have:

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

EDIT: Here's a really evil way to accomplish this that you should not do:

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

You could access it directly on the anonymous class creation expression:

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

But then, you can't otherwise use the object created anymore, so it's kinda useless.

Java is not a C#, if I'am not mistaken such syntax sugar is allowed there. You can have a look at sun.reflect.MagicAccessorImpl. But this class is not a common practice. Used only for auto generated code. If you extend MagicAccessorImpl JVM will not perform field access level check. So you can do thing like this:

// ----- 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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top