使用反射实例化匿名Java类

时间:2020-09-23 14:15:52

标签: java reflection anonymous-class anonymous-inner-class java-reflection

是否可以使用反射实例化一个匿名Java类。 我创建了一个匿名类,稍后我想再次实例化它,是否可以这样做? 我可以使用一个内部类来做到这一点,但是我真的需要使用一个匿名类吗?

2 个答案:

答案 0 :(得分:3)

该语言的设计说明:不,匿名类不能实例化,除非在您使用过的那个地方。

在实践中:是的,您可以,但是,因为规范并未说明您可以这样做(实际上,该规范建议您不能但不保证不能这样做),无论您编写要做什么这可能(并且可能会!)在更高版本的Java中中断。当然,生成的类文件(这是一个更新的VM / classfile概念)将是其他文件的嵌套,并且模块系统会带来更严格的限制。

关于生成的类的实际名称,您也会在黑暗中陷入困境。

换句话说,“在您停止询问方式之前,也许您应该考虑一下原因”,然后重新考虑,因为不是这样。如果您以后需要再次使用它,请给它命名。那就是名字的意思。

所以,概念证明-但是不要这样做,这很愚蠢,会弹出,中止


class Test {
        public static void main(String[] args) throws Exception {
                Runnable r = new Runnable() { public void run() {
                        System.out.println("Hello!");
                }};

                r.run();
                Class<?> c = Class.forName("Test$1");
                Object o = c.getDeclaredConstructor().newInstance();
                ((Runnable) o).run();
        }
}

以上内容实际上适用于我的特定版本的Java,我的体系结构以及月球的当前阶段。明天可能不工作。还要注意,这样的事情的构造函数可能令人惊讶:例如,在这种情况下,匿名内部类是在静态方法内部进行的,因此没有“ this”自变量(通常将实例传递)。 Java是否会意识到您不使用匿名类中的Test.this中的任何内容,因此是否忽略内部类中的取决于Java。您可以通过查询所有构造函数(.getDeclaredConstructors())来解决此问题,但是为什么要编写大量非常棘手且易于出错的代码,只是为了破解明天可能会失败的东西?

请。不要。

答案 1 :(得分:0)

我想你可以。使用标准反射

class Test {
    public static void main(String[] args) throws Exception {
        Runnable r = new Runnable() { public void run() {
            System.out.println("Hello!");
        }};

       
        Class<?> clazz = r.getClass();
        Object instance = clazz.newInstance();
        System.out.println(instance); // Test$1@7c16905e
        System.out.println(instance == r); // false
        Method method = clazz.getMethod("run");
        method.invoke(instance); // Hello!
    }
}

假设我们定义了一个匿名类,但是没有将其实例保存到r。然后我们可以使用Spoon

src / main / java / Test.java

import spoon.Launcher;
import spoon.reflect.CtModel;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtType;
import spoon.reflect.visitor.Filter;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        new Runnable() {
            public void run() {
                System.out.println("Hello!");
            }
        };

        Launcher launcher = new Launcher();
        launcher.addInputResource("src/main/java/Test.java");
        CtModel model = launcher.buildModel();
        Class<?> clazz = model
                .getElements((Filter<CtClass<?>>) CtClass::isAnonymous)
                .stream()
                .map(CtType::getActualClass)
                .findFirst().get();
        Object instance = clazz.newInstance();
        System.out.println(instance); //Test$1@3fb1549b
        Method method = clazz.getMethod("run");
        method.invoke(instance); // Hello!
    }
}

pom.xml

<dependency>
    <groupId>fr.inria.gforge.spoon</groupId>
    <artifactId>spoon-core</artifactId>
    <version>8.2.0</version>
</dependency>