Is it possible to create an instance of inner class using Java Reflection?
Sample of code:
public class Foo
{
public class Bar
{
public void printMesg(String body)
{
System.out.println(body);
}
}
public static void main(String[] args)
{
// Creating new instance of 'Bar' using Class.forname - how?
}
}
Is it possible to create new instance of class Bar giving its name? I tried to use:
Class c = Class.forName("Foo$Bar")
it finds the class, but when i use c.newInstance() it throws InstantiationException.
Solution 1:
You need to jump through a few hoops to do this. First, you need to use Class.getConstructor() to find the Constructor
object you want to invoke:
Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. The parameterTypes parameter is an array of Class objects that identify the constructor's formal parameter types, in declared order. If this Class object represents an inner class declared in a non-static context, the formal parameter types include the explicit enclosing instance as the first parameter.
And then you use Constructor.newInstance():
If the constructor's declaring class is an inner class in a non-static context, the first argument to the constructor needs to be the enclosing instance
Solution 2:
Inner classes can indeed not be constructed without constructing the parent class first. It cannot exist outside the parent class. You'll have to pass an instance of the parent class in when doing reflection. Nested classes are static
and they can be used independently from the parent class, thus also when doing reflection.
Here's an SSCCE which demonstrates all the stuff.
package mypackage;
import java.lang.reflect.Modifier;
public class Parent {
public static class Nested {
public Nested() {
System.out.println("Nested constructed");
}
}
public class Inner {
public Inner() {
System.out.println("Inner constructed");
}
}
public static void main(String... args) throws Exception {
// Construct nested class the normal way:
Nested nested = new Nested();
// Construct inner class the normal way:
Inner inner = new Parent().new Inner();
// Construct nested class by reflection:
Class.forName("mypackage.Parent$Nested").newInstance();
// Construct inner class by reflection:
Object parent = Class.forName("mypackage.Parent").newInstance();
for (Class<?> cls : parent.getClass().getDeclaredClasses()) {
if (!Modifier.isStatic(cls.getModifiers())) {
// This is an inner class. Pass the parent class in.
cls.getDeclaredConstructor(new Class[] { parent.getClass() }).newInstance(new Object[] { parent });
} else {
// This is a nested class. You can also use it here as follows:
cls.getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {});
}
}
}
}
This should produce
Nested constructed Inner constructed Nested constructed Inner constructed Nested constructed
Solution 3:
Quick and dirty code:
Foo.Bar.class.getConstructors()[0].newInstance(new Foo());
Explanation: You must tell the Bar about its enclosing Foo.
Solution 4:
Yes. Remember you need to feed the outer instance to an inner class. Use javap
to find the constructor. You will need to go through java.lang.reflect.Constructor
rather than rely upon the evil Class.newInstance
.
Compiled from "Foo.java"
public class Foo$Bar extends java.lang.Object{
final Foo this$0;
public Foo$Bar(Foo);
public void printMesg(java.lang.String);
}
javap -c
is interesting on the constructor because (assuming -target 1.4
or later, now implicit) you get an assignment of an instance field before calling the super constructor (used to be illegal).
public Foo$Bar(Foo);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LFoo;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: return