【问题标题】:Possible to change the outer class instance of an inner class in Java?可以在 Java 中更改内部类的外部类实例吗?
【发布时间】:2010-03-02 23:00:07
【问题描述】:

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

【问题讨论】:

  • 除了它在未来的混淆Java竞赛中的潜力之外,还有什么意义?您知道,如果您想要一个可以与其父级解除关联的内部类,您可以将其声明为静态,对吗?
  • 我觉得这个问题很有趣。有谁知道在 JLS 中的哪个位置指定了指向外部类的指针的命名方式?通过实验,我发现它似乎是this$0,并根据需要附加了尽可能多的$(可能没有)。这实际上是指定的吗?
  • 好的,我刚刚发现第二级内部类使用 this$1 代替。令人着迷!
  • @Steve:这个问题纯粹是出于好奇。我无意使用此功能
  • @polygenelubricants - afaik,JLS 没有指定这一点。它(至少在理论上)是特定于 JVM/编译器实现的。这也是为什么做这种事情很疯狂的另一个原因。

标签: java


【解决方案1】:

是的,这是可能的,尽管对我来说这听起来很糟糕。想法是使用反射将否则 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 可以强制执行禁止此操作成功的策略。

【讨论】:

    【解决方案2】:

    如果您说的是实例化时间,可以使用以下语法:

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

    【讨论】:

      【解决方案3】:

      你应该可以,使用反射。

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

      由于该字段似乎是 final,您可以查看 this article 以了解如何规避它。

      也就是说,您根本不需要这样做 - 这将是一个没有实际收益的双重丑陋黑客。

      【讨论】:

        猜你喜欢
        • 2014-08-21
        • 2016-01-21
        • 2020-04-07
        • 2018-01-19
        • 2014-10-12
        • 1970-01-01
        • 2011-08-11
        • 2014-09-09
        • 1970-01-01
        相关资源
        最近更新 更多