2010-03-02 70 views
9

在Java中,每當創建內部類實例時,它都會與外部類的實例關聯。出於好奇,是否有可能將內部類與外部類的另一個實例相關聯?可能在Java中更改內部類的外部類實例嗎?

+0

除了未來混淆java比賽中的潛力之外,還有什麼意義呢?你知道,如果你想要一個內部類可以從它的父母解除關聯,你可以聲明它是靜態的,對吧? – 2010-03-03 00:27:31

+0

我覺得這個問題很有趣。有誰知道在JLS中指定了外部類的指針是如何命名的?通過實驗,我發現它似乎是'this $ 0',根據需要附加了許多'$'(可能沒有)。這實際上是指定的嗎? – polygenelubricants 2010-03-03 00:33:49

+0

好的,我剛剛發現第二層的內部類使用'this $ 1'來代替。迷人! – polygenelubricants 2010-03-03 00:37:23

回答

6

是的,這是可能的,雖然這聽起來像一個非常糟糕的主意給我。我們的想法是使用反射來設置指向外部實例的其他指針(不保證成功)。

import java.lang.reflect.*; 

public class Me { 
    final String name; 

    Me(String name) { 
     this.name = name; 
    } 

    class InnerMe {  
     String whoAreYou() { 
      return name; 
     } 
    } 

    InnerMe innerSelf() { 
     return new InnerMe(); 
    } 

    public static void main(String args[]) throws Exception { 
     final Me me = new Me("Just the old me!"); 
     final InnerMe innerMe = me.innerSelf(); 
     System.out.println(innerMe.whoAreYou()); // "Just the old me!" 
     Field outerThis = innerMe.getClass().getDeclaredFields()[0]; 
     outerThis.setAccessible(true); 
     outerThis.set(innerMe, new Me("New and improved me!")); 
     System.out.println(innerMe.whoAreYou()); // "New and improved me!" 
    } 

} 

這裏的關鍵部分是outerThis.setAccessible(true); - 一個SecurityManager可以強制執行禁止這種得手的政策。

4

您應該可以使用反射。

剛剛得到內部類(getClass().getDeclaredFields())的各個領域,看看哪些字段保存父,然後改變它(使用field.set(innerInstance, newParent)之前,你應該訪問的領域 - setAccessible(true)

由於現場出現是final,你可以看看this article看看如何繞過這個。

這就是說,你根本不需要這樣做 - 這將是一個雙倍醜陋的黑客沒有實際收益。

5

如果你正在談論實例化時,有可能使用的語法如下:

public class Outer { 
    public class Inner {} 
} 
... 
Outer o = new Outer(); 
Outer.Inner i = o.new Inner(); 

但是,這是不可能的(不setAccessible(true)),以內部類的現有實例與外部類的其他實例相關聯由於現場指向外圍實例是final

javap Outer$Inner 

Compiled from "Outer.java" 
public class Outer$Inner extends java.lang.Object{ 
    final Outer this$0; 
    public Outer$Inner(Outer); 
} 
+0

(+1)與'final'相得益彰。 – Bozho 2010-03-02 23:55:09

+0

+1 for'o.new Inner()' - 今天我學到了一種新的語法。 – 2012-03-02 22:17:24