2010-03-02 68 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