Is it possible to instantiate a nested class using Java Reflection?

Code example:

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 a new instance of the Bar class with its name? I tried using:

 Class c = Class.forName("Foo$Bar") 

it finds the class, but when I use c.newInstance (), it throws an ExceptionExceptionException.

+33
java reflection inner-classes
Jan 19 '10 at 23:20
source share
7 answers

You need to jump over several hoops to do this. First, you need Class.getConstructor () to find the Constructor object you want to call:

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 constructive formal parameter types in the declared order. If this class object is an inner class declared in a non-stationary context, formal parameter types include an explicitly included instance as the first parameter.

And then you use Constructor.newInstance () :

If the constructor declaring the class is an inner class in a non-stationary context, the first argument to the constructor must be an instance

+54
Jan 19 '10 at 23:25
source share

Inner classes really cannot be built without creating a parent class. It cannot exist outside the parent class. You will need to pass an instance of the parent class when doing the reflection. Nested classes are static , and they can be used regardless of the parent class, as well as when reflected.

Here's an SSCCE that demonstrates everything.

 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[] {}); } } } } 

It should produce

 Nested constructed
 Inner constructed
 Nested constructed
 Inner constructed
 Nested constructed
+25
Jan 19 '10 at 23:47
source share

Quick and dirty code:

 Foo.Bar.class.getConstructors()[0].newInstance(new Foo()); 

Explanation: You must inform Bar about the inclusion of Foo.

+7
Jan 19 '10 at 23:29
source share

Yes. Remember that you need to feed the outer instance with the inner class. Use javap to find the constructor. You need to go through java.lang.reflect.Constructor , and not rely on 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 interesting to the constructor because (assuming -target 1.4 or later is now implicit) you get the assignment of an instance field before calling the super constructor (which was 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 
+2
Jan 19 '10 at 23:24
source share

Other answers explained how you can do what you want.

But I want to offer you that the fact that you need to do this at all is a sign that there is something wrong with your system design. I would suggest that you need either the (non-static) factory method for the surrounding class, or you need to declare the inner class static.

Creating an (non-static) instance of the inner class reflexively has the β€œsmell” of broken encapsulation.

+1
Jan 20 '10 at 1:28
source share

This is not entirely optimal, but it works for the depths of inner classes and inner static classes.

 public <T> T instantiateClass( final Class<T> cls ) throws CustomClassLoadException { try { List<Class<?>> toInstantiate = new ArrayList<Class<?>>(); Class<?> parent = cls; while ( ! Modifier.isStatic( parent.getModifiers() ) && parent.isMemberClass() ) { toInstantiate.add( parent ); parent = parent.getDeclaringClass(); } toInstantiate.add( parent ); Collections.reverse( toInstantiate ); List<Object> instantiated = new ArrayList<Object>(); for ( Class<?> current : toInstantiate ) { if ( instantiated.isEmpty() ) { instantiated.add( current.newInstance() ); } else { Constructor<?> c = current.getConstructor( instantiated.get( instantiated.size() - 1 ).getClass() ); instantiated.add( c.newInstance( instantiated.get( instantiated.size() - 1 ) ) ); } } return (T) instantiated.get( instantiated.size() - 1 ); } catch ( InstantiationException e ) { throw new CustomClassLoadException( "Failed to load class.", e ); } catch ( IllegalAccessException e ) { throw new CustomClassLoadException( "Failed to load class.", e ); } catch ( SecurityException e ) { throw new CustomClassLoadException( "Failed to load class.", e ); } catch ( NoSuchMethodException e ) { throw new CustomClassLoadException( "Failed to load class.", e ); } catch ( IllegalArgumentException e ) { throw new CustomClassLoadException( "Failed to load class.", e ); } catch ( InvocationTargetException e ) { throw new CustomClassLoadException( "Failed to load class.", e ); } } 
0
Nov 01 '13 at 17:03
source share

Here's the answer for a nested class (static inner): In my case, I need to get the type by its full name

 Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance(); 

" $ " is crucial!

with a dot, you get a ClassNotFoundException for the class "package.innerClass.outerClass". The exception is omissions: - (.

-one
May 14 '13 at 10:42
source share



All Articles