简体   繁体   English

使用反射实例化一个匿名 Java 类

[英]Instantiate an anonymous Java class using reflection

Is it possbile to instantiate an anonymous Java class using reflection.是否可以使用反射实例化匿名 Java 类。 I have created an anonymous class that I would like to instantiate again later on, is there anyway of doing this?我创建了一个匿名类,我想稍后再次实例化,无论如何要这样做吗? I can do it with an inner class, but I really need to do it with an anonymous one?我可以用内部类来做,但我真的需要用匿名类来做吗?

The design of the language says: No, anonymous classes cannot be instantiated except in that one place where you used it.该语言的设计说:不,匿名类不能被实例化,除非在你使用它的地方。

In practice: Yeah, you can, but, because the specification doesn't say you can (in fact, the specification suggests you can't but doesn't promise that you can't), whatever you write to do this, may (and probably will!) break in a later version of java.在实践中:是的,你可以,但是,因为规范没有说你可以(事实上,规范表明你不能但不承诺你不能),无论你写什么来做到这一点,都可能(并且可能会!)在更高版本的 java 中中断。 Certainly the class file generated will be (this is a newer VM/classfile concept) a nestmate of the other ones, and the module system brings more serious restrictions.当然生成的类文件(这是一个较新的VM/类文件概念)是其他类文件的嵌套,并且模块系统带来了更严重的限制。

You're also take a wild stab in the dark as to the actual name of the class generated.对于生成的类的实际名称,您还会在黑暗中进行疯狂的尝试。

In other words, 'before you stop to ask how, perhaps you should think about why', and then reconsider, because this isn't it.换句话说,“在你停下来问怎么做之前,也许你应该考虑一下为什么”,然后重新考虑,因为事实并非如此。 If you have a need to use it again later, then name the thing.如果您以后需要再次使用它,请为该事物命名。 That's what names are for.这就是名字的用途。

So, the proof of concept - but do not do this, this is silly, eject, abort :所以,概念证明 - 但不要这样做,这是愚蠢的,弹出,中止


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

The above actually works on my particular version of java, my architecture, and the current phase of the moon.以上实际上适用于我的特定 Java 版本、我的架构和当前的月相。 It may not work tomorrow.明天可能行不通。 Also note that the constructor of such a thing is perhaps surprising: For example, in this case, the anonymous inner class is made inside a static method and therefore, there is no 'this' argument (normally, the instance is passed along).还要注意,这种东西的构造函数可能令人惊讶:例如,在这种情况下,匿名内部类是在静态方法中创建的,因此没有“this”参数(通常,实例被传递)。 Whether java will realize that you don't use anything from Test.this inside your anonymous class and therefore omits that from the inner class or not is up to java. java 是否会意识到您在匿名类中没有使用Test.this任何内容,因此是否从内部类中省略了它取决于 java。 You can work around that by querying for all constructors ( .getDeclaredConstructors() ), but why are you writing a ton of extremely tricky and error-prone code just to hack around something that will likely fail tomorrow?您可以通过查询所有构造函数( .getDeclaredConstructors() )来解决这个问题,但是为什么要编写大量极其棘手且容易出错的代码来解决明天可能会失败的问题?

Please.请。 Don't.别。

I guess you can.我想你可以。 Using standard reflection使用标准反射

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!
    }
}

Suppose we defined an anonymous class but didn't save its instance to r .假设我们定义了一个匿名类,但没有将其实例保存到r Then we can use Spoon然后我们可以使用勺子

src/main/java/Test.java 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 pom.xml

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM