views:

422

answers:

5

It's been about 6 years since I've written Java, so please excuse the rust.

I'm working with a library method that requires that I pass it Class objects. Since I'll have to invoke this method a dynamic number of times, each time with a slightly different Class argument, I wanted to pass it an anonymous class.

However, all the documentation/tutorials I've been able to find so far only talk about instantiating anonymous classes, e.g.:

new className(optional argument list){classBody}

new interfaceName(){classBody}

Can I define an anonymous class without instantiating it? Or, perhaps more clearly, can I create a Class object for an anonymous class?

A: 

You can only reference an anonymous class ONCE. If you do not instantiate it there, you cannot instantiate it since you do not have a name for it.

Hence I believe that anonymous classes can only be used in conjunction with a "new BaseClass()".

In your situation you would pass a BaseClass object to your method doing the work, and instantiate the anonymous object in the source code when you need the object to pass.

Thorbjørn Ravn Andersen
It's not my method, it's a library I'm using. It needs the `Class` because it creates more than one instantiation. So passing it an instance won't work.
rampion
Then anonymous classes will not work. Perhaps nested classes instead?
Thorbjørn Ravn Andersen
+1  A: 

Unfortunately, there's no way you can dodge the instantiation here. You can make it a no-op, however:

foo((new Object() { ... }).getClass());

Of course, this might not be an option if you have to derive from some class that performs some actions in constructor.

EDIT

Your question also says that you want to call foo "each time with a slightly different Class argument". The above won't do it, because there will still be a single anonymous inner class definition, even if you put the new-expression in a loop. So it's not really going to buy you anything compared to named class definition. In particular, if you're trying to do it to capture values of some local variables, the new instance of your anonymous class that foo will create using the Class object passed to it will not have them captured.

Pavel Minaev
Thanks for the details in the EDIT. Could I pass it a member inner class instead, and have that member inner class refer to some instance variable of the parent class? I'm not sure whether member inner classes can be passed. I guess I could always fall back on a regular class with some static parameters that I can modify between calls.
rampion
No. You cannot "create classes at runtime", so to speak. Variable capture (including capture of `this`) works on instance level, not on class level. What it in fact does is just add a few hidden parameters to constructor of your inner class, and pass the values in them. Obviously that only works when you create the instance right there and let compiler do its magic.
Pavel Minaev
+1  A: 

short answer

you cannot (using only JDK classes)

long answer

give it a try:

public interface Constant {

    int value();
}

public static Class<? extends Constant> classBuilder(final int value) {
    return new Constant() {

        @Override
        public int value() {
            return value;
        }

        @Override
        public String toString() {
            return String.valueOf(value);
        }
    }.getClass();
}

let's creating two new class "parametric" classes:

Class<? extends Constant> oneClass = createConstantClass(1);
Class<? extends Constant> twoClass = createConstantClass(2);

however you cannot instantiate this classes:

Constant one = oneClass.newInstance(); // <--- throws InstantiationException
Constant two = twoClass.newInstance(); // <--- ditto

it will fail at runtime since there is only one instance for every anonymous class.

However you can build dynamic classes at runtime using bytecode manipulation libraries such ASM. Another approach is using dynamic proxies, but this approach as the drawback that you can proxy only interface methods (so you need a Java interface).

dfa
A: 

You can't access the Class object of an anonymous class without instatiating it. However, if you only need access to the class, you could define local classes within your method and refer to these using the ClassName.class literal syntax.

Ben Lings
Although this probably won't help you if you're trying to capture local variables because I don't think the method you are passing it to will be able to instatiate it.
Ben Lings
A: 

You can assume the name of an anonymous class and do a Class.forName("mypackage.MyBaseClass$1") to get a handle to an anonymous class. This will give you the first anonymous class defined in your MyBaseClass so this is rather fragile way to refer to a class.

I suspect whatever you are trying to do could be done a better way. What are you really trying to achieve and perhaps we can suggest a way which doesn't require you to pass a Class this way.

Peter Lawrey