簡體   English   中英

如何在沒有反射的情況下訪問匿名對象內聲明的字段?

[英]How to access fields declared inside anonymous object without reflection?

可以使匿名類在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);
   }
}

但是在這個例子中無法訪問它們,因為oObject類型:

$ 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成為合適的類型以便我可以獲得ox (請注意, 可以使用反射執行此操作 ,但我想靜態執行此操作)。

這個類有一個名字。 這是A$1 但是,您無法在編譯時訪問它(編譯器為您創建A$1 )。 因此,您無法在沒有反射的情況下訪問該字段。

如果您在Eclipse中,則可以使用“ 源”菜單( Alt Shift S )→“ 將匿名類轉換為嵌套”將其自動轉換為“真實”類。

或者,您可以:

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

您可以直接在匿名類創建表達式上訪問它:

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

但是,你不能再使用創建的對象了,所以它有點無用。

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
}

取自這里

像這樣

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM