1

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
  • Does my answer work for you? Commented Sep 26, 2020 at 9:15

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Why is it necessary to look for Class<?> by name (which is implementation-dependent)?
If you don't want to guess how class names are encoded you can do r.getClass().getName().
Ok, maybe you meant that we defined an anonymous class but didn't save its instance to r.
Please see my answer.
0

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.