如何从 SubClass 实例中获取定义的 class 实例?

How to get the defining class instance from the SubClass instance?

如果我有这个代码:

public class MySuperClass {
    public String superString = "hello";

    public MyChildClass makeChild() {
        return new MyChildClass();
    }

    public class MyChildClass {
        public String childString = "hi";
    }
}

如何从 MyChildClass 实例中获取 MySuperClass 实例? 因为我有这个错误:

关于 Whosebug 有非常相似的问题,但这不是其中任何一个的重复。 我的代码有什么错误?如果不在嵌套的 class which returns MySuperClass.this 中创建方法,我怎样才能实现我上面所说的?假设我不拥有 MySuperClass 的代码...

我认为这是可以做到的,因为在 MyChildClass 中我可以使用 MySuperClass.this 访问超级实例,我如何从子 class 外部获取附加到子的 MySuperClass 实例?

编辑:我知道转换不是实现此目的的方法,这是实现我想要的东西的尝试

你在混淆术语。 “Child class”几乎总是用于这种关系:

public class Parent {}
public class Child extends Parent {}

(这里的'Parent'被称为Child的'superclass')。

在这种情况下,'how can I get my superclass from my child class' 毫无意义。 Child 是 Parent 的扩展,当你写 new Child() 时只有一个实例,而那个实例是 Child 和 [=96 中的东西的组合=].这不是两个独立的东西。

你说的是inner classes。这种关系:

public class Outer {
    public class Inner {}
}

Inner/Outer 对比 Child/Parent 或 Sub/Super.

那么,您实际要问的是:如何获取外部 class 实例?

那不可能。它是 Inner 的一个实现细节,由 Inner 来公开它。如果它不想访问,您将无法访问它。

但也有破解方法和解决方法。

选项#1:Inner中的代码本身就可以做到

class Inner {} 附带的 {} 中,您可以这样做:

class Outer {
    class Inner {
        public Outer getOuterInstance() {
            return Outer.this;
        }
    }
}

选项 #2:破解它

在 class/JVM 级别,inner/outer classes 不存在。它们都只是 classes。这就是为什么,如果你编译上面的内容,你最终会得到 2 个 class 文件,而不是一个:Outer.classOuter$Inner.class。 Inner 拥有的外部实例由一个字段表示。

这个字段一般叫做this[=19=],是包私有的。所以,像这样:

Field f = Inner.class.getDeclaredField("this[=13=]");
f.setAccessible(true);
Outer outer = (Outer) f.get(instanceOfInner);

但是,如果反射代码没有为您说明这一点:不要。这是一个可怕的想法。 SecurityManager 可以阻止你。代码很难阅读,this[=19=] 没有意义,除非你用注释来解释你在做什么。最重要的是,就像任何反射一样,这完全不是 Outer/Inner 的作者打算让你做的事情,而且无论你使用 Outer 做什么,在一些小的点上都可能无法 'work' 正确地发布道路,因为您没有以预期的方式使用这个库,因此为它提供的任何支持都将丢失。你自己铺路,这很糟糕,因为你不知道作者的真正意图,你现在实际上不得不说你的库必须在没有广泛测试的情况下永远不会更新,而不更新是让你自己被黑的好方法.这在很多方面都是一个坏主意。

此外,当前 OpenJDK 团队表示对向后兼容性的关注显着减少(请参阅 jigsaw 项目,这是很长一段时间以来 java 最具破坏性的版本,OpenJDK 团队几乎决定获得在单个版本跳转中摆脱 SecurityManager 直到被社区召回,积极扩展大多数毫无意义的 'opens' 检查,等等) - 意味着如果你依赖它,如果 java18 或其他不会永久破坏您执行此操作的能力。

所以,不要这样做

警告:non-static 内部 class 不好。

内部 class 实际上有一个外部类型的不可见字段的想法既烦人又令人惊讶。它停止垃圾收集。它会让普通的 java 程序员感到困惑,因为 'using' 这个 java 功能很少见。

因此,我强烈建议您始终将内部 class 设为 static,如果您真的想要 Outer 的实例,请明确说明:设为 Inner静态,然后给它一个 private final Outer outer; 字段。

它同样高效,输入的内容稍微多一些,但可读性更高。