Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 844
kars7e Avatar asked Jan 19 '10 23:01

kars7e


People also ask

How do you create an instance of an inner class in Java?

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.

How do you create an instance of a reflection in Java?

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.

Can we create inner class in Java?

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.

Can you instantiate an inner class?

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.


4 Answers

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

like image 127
skaffman Avatar answered Oct 10 '22 12:10

skaffman


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
like image 32
BalusC Avatar answered Oct 10 '22 11:10

BalusC


Quick and dirty code:

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

Explanation: You must tell the Bar about its enclosing Foo.

like image 7
meriton Avatar answered Oct 10 '22 13:10

meriton


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
like image 2
Tom Hawtin - tackline Avatar answered Oct 10 '22 11:10

Tom Hawtin - tackline