可以在Java中更改内部类的外部类实例吗?

时间:2010-03-02 23:00:08

标签: java

在Java中,每当创建内部类实例时,它都与外部类的实例相关联。出于好奇,是否可以将内部类与外部类的另一个实例相关联?

3 个答案:

答案 0 :(得分:6)

是的,这是可能的,虽然这听起来对我来说真的很糟糕。我们的想法是使用反射设置指向外部实例的其他final指针(不能保证成功)。

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可以强制执行禁止此功能成功的政策。

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

答案 2 :(得分:4)

你应该可以使用反射。

只需获取内部类的所有字段(getClass().getDeclaredFields())并查看哪个字段包含父项,然后更改它(使用field.set(innerInstance, newParent)。在此之前,您应该使字段可访问 - {{1} })

由于该字段似乎是setAccessible(true),您可以查看this article以了解如何规避该问题。

那就是说,你根本不应该这样做 - 这将是一个双重丑陋的黑客,没有实际收益。