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?
2 Answers
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("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. 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.
4 Comments
Class<?> by name (which is implementation-dependent)?r.getClass().getName().r.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. 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("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>