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.
To instantiate an inner class, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax: OuterClass. InnerClass innerObject = outerObject.
We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don't have the classes information at compile time, we can assign it to Object and then further use reflection to access it's fields and invoke it's methods.
Java Inner Classes In Java, it is also possible to nest classes (a class within a class). The purpose of nested classes is to group classes that belong together, which makes your code more readable and maintainable.
An instance of InnerClass can exist only within an instance of OuterClass and has direct access to the methods and fields of its enclosing instance. To instantiate an inner class, you must first instantiate the outer class.
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
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
Quick and dirty code:
Foo.Bar.class.getConstructors()[0].newInstance(new Foo());
Explanation: You must tell the Bar about its enclosing Foo.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With