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

huangapple go评论63阅读模式
英文:

Instantiate an anonymous Java class using reflection

问题

可以使用反射来实例化一个匿名的Java类吗?
我已经创建了一个匿名类,然后我想以后再次实例化它,有没有任何方法可以做到这一点?
我可以为内部类做到,但我真的需要用匿名类来实现吗?

英文:

Is it possbile to instantiate an anonymous Java class using reflection.
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?

答案1

得分: 3

以下是翻译好的部分:

语言设计说:不,匿名类只能在你使用它的地方实例化。

实际上:是的,你可以,但是因为规范没有说你可以(事实上,规范暗示你不能,但并不保证你不能),无论你写什么来实现这一点,都可能(而且很可能!)在以后的Java版本中出问题。当然,生成的类文件将是(这是一个较新的VM/classfile概念)其他类的一个nestmate,并且模块系统带来了更严重的限制。

你还会对生成的类的实际名称进行猜测。

换句话说,在你停下来问“如何”之前,也许你应该考虑一下“为什么”,然后重新考虑,因为这不是解决方法。如果以后需要再次使用它,那就给这个东西取个名字。这就是名称的作用。

因此,这只是概念验证 - 但不要这样做,这是愚蠢的,退出,中止

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())来解决这个问题,但是为什么要编写大量极其棘手和容易出错的代码,仅仅为了绕过明天可能失败的东西呢?

拜托,别这样做。

英文:

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. 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.

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(&quot;Hello!&quot;);
                }};

                r.run();
                Class&lt;?&gt; c = Class.forName(&quot;Test$1&quot;);
                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. 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). 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. 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?

Please. Don't.

答案2

得分: 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][1]

*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>


  [1]: http://spoon.gforge.inria.fr/

希望这可以帮助您。如果您需要进一步的帮助,请随时提问。

英文:

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(&quot;Hello!&quot;);
}};
Class&lt;?&gt; clazz = r.getClass();
Object instance = clazz.newInstance();
System.out.println(instance); // Test$1@7c16905e
System.out.println(instance == r); // false
Method method = clazz.getMethod(&quot;run&quot;);
method.invoke(instance); // Hello!
}
}

Suppose we defined an anonymous class but didn't save its instance to r. Then we can use 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(&quot;Hello!&quot;);
}
};
Launcher launcher = new Launcher();
launcher.addInputResource(&quot;src/main/java/Test.java&quot;);
CtModel model = launcher.buildModel();
Class&lt;?&gt; clazz = model
.getElements((Filter&lt;CtClass&lt;?&gt;&gt;) CtClass::isAnonymous)
.stream()
.map(CtType::getActualClass)
.findFirst().get();
Object instance = clazz.newInstance();
System.out.println(instance); //Test$1@3fb1549b
Method method = clazz.getMethod(&quot;run&quot;);
method.invoke(instance); // Hello!
}
}

pom.xml

&lt;dependency&gt;
&lt;groupId&gt;fr.inria.gforge.spoon&lt;/groupId&gt;
&lt;artifactId&gt;spoon-core&lt;/artifactId&gt;
&lt;version&gt;8.2.0&lt;/version&gt;
&lt;/dependency&gt;

huangapple
  • 本文由 发表于 2020年9月23日 22:15:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/64029951.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定