Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiate private inner class with java reflection

Is it possible to instantiate a private inner class from another class using Java reflection. For example if I took this code

public class Main {
    public static void main(String[] args) {}
}

class OtherClass {
    private class Test {}
}

is it possible to instantiate and gain access to Test from the main method in the class main.

like image 865
popgalop Avatar asked Jan 01 '13 16:01

popgalop


People also ask

How do you instantiate a private inner class in Java?

Accessing the Private Members To instantiate the inner class, initially you have to instantiate the outer class. Thereafter, using the object of the outer class, following is the way in which you can instantiate the inner class.

Can we instantiate a private class in Java?

Yes, you can instantiate a private inner class with Java reflection. To do that, you need to have an instance of outer class and invoke the inner class constructor which will use outer class instance in its first argument.

How do you access private class using reflection?

If we want to access Private Field and method using Reflection we just need to call setAccessible(true) on the field or method object which you want to access. Class. getDeclaredField(String fieldName) or Class. getDeclaredFields() can be used to get private fields.

Can we call private method using reflection Java?

You can access the private methods of a class using java reflection package.


Video Answer


3 Answers

Yes, you can instantiate a private inner class with Java reflection. To do that, you need to have an instance of outer class and invoke the inner class constructor which will use outer class instance in its first argument.

class OuterClass {
    private class InnerClass {
        {
            //this block is just to confirm that the inner object was created
            //it will be added to every constructor of this class
            System.out.println("inner object created");
        }
    }
}

When we don't know name of private inner class and we assume that it has no-argument constructor:

class Main {

    //no comment version
    public static Object giveMeInnerInstance() throws Exception{
        OuterClass outerObject = new OuterClass();
        Class<?> innerClass = OuterClass.class.getDeclaredClasses()[0];
        Constructor<?> constructor = innerClass.getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        return constructor.newInstance(outerObject);
    }

    //commented version
    public static void main(String[] args) throws Exception {
        //we need an outer class object to use the inner object constructor
        //(the inner class object needs to know about its parent object)
        OuterClass outerObject = new OuterClass();

        //let's get the inner class 
        //(we know that the outer class has only one inner class, so we can use index 0)
        Class<?> innerClass = OuterClass.class.getDeclaredClasses()[0];
        //or if we know name of inner class we can use 
        //Class<?> innerClass = Class.forName("full.package.name.OuterClass$InnerClass")

        //since constructor so we could use it to pass instance of outer class and change 
        //its accessibility. We can use this code to get default constructor of InnerClass 
        //since we know that this is the only constructor here
        Constructor<?> constructor = innerClass.getDeclaredConstructors()[0];
        //we could also use 
        //Constructor<?> constructor = innerClass.getDeclaredConstructor(OuterClass.class);

        //the default constructor of the private class has same visibility that class has
        //so it is also private, so to be able to use it we need to make it accessible
        constructor.setAccessible(true);

        //now we are ready to create inner class instance
        Object innerObject = constructor.newInstance(outerObject);
    }
}

Now we can make this code clearer if we have informations like

  • name of inner class,
  • constructor arguments

So instead of checking list of inner classes and picking first one, we can get selected inner class by its name using

Class<?> inner = Class.forName("our.pack.age.OuterClass$InnerClass")
//                                                     ^^^^^^^^^^^

Similarly we can select constructor we want to use by invoking getDeclaredConstructor(outerType,rest,of,parameter,types) so if our inner class would look like

class OuterClass {
    private class InnerClass {

        private int x;

        public InnerClass(int x) {
            this.x = x;
            System.out.println("inner object created");
        }

    }
}

our code could be

class ReflectionDemo {

    //no comment version
    public static Object giveMeInnerInstance() throws Exception{
        OuterClass outerObject = new OuterClass();
        Class<?> innerClass = Class.forName("com.stackoverflow.q14112166.OuterClass$InnerClass");
        Constructor<?> constructor = innerClass.getDeclaredConstructor(OuterClass.class, int.class);
        constructor.setAccessible(true);
        return constructor.newInstance(outerObject,42);
    }

    public static Object getFieldValue(Object obj, String fieldName) throws Exception{
        Class<?> clazz = obj.getClass();
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(obj);
    }

    //lets test our code
    public static void main(String[] args) throws Exception {
        Object innerClassObject = giveMeInnerInstance();
        System.out.println(getFieldValue(innerClassObject, "x"));           
    }
}

Output:

inner object created
42
like image 179
Pshemo Avatar answered Oct 11 '22 23:10

Pshemo


When using reflection, you'll find constructors of that inner class taking an instance of the outer class as an additional argument (always the first) .

See these questions for related information:

  • Instantiating inner class

  • How can I instantiate a member class through reflection on Android

  • In Java, how do I access the outer class when I'm not in the inner class?

Example:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class OuterClass {

    private class InnerClass {

    }

    public OuterClass() {
        super();
    }

    public static void main(String[] args) {
        // instantiate outer class
        OuterClass outer = new OuterClass();

        // List all available constructors.
        // We must use the method getDeclaredConstructors() instead
        // of getConstructors() to get also private constructors.
        for (Constructor<?> ctor : OuterClass.InnerClass.class
                .getDeclaredConstructors()) {
            System.out.println(ctor);
        }

        try {
            // Try to get the constructor with the expected signature.
            Constructor<InnerClass> ctor = OuterClass.InnerClass.class
                    .getDeclaredConstructor(OuterClass.class);
            // This forces the security manager to allow a call
            ctor.setAccessible(true);

            // the call
            try {
                OuterClass.InnerClass inner = ctor.newInstance(outer);
                System.out.println(inner);
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
like image 21
Sam Avatar answered Oct 12 '22 00:10

Sam


You can do the following :

public static void main(String[] args) throws Exception {
    // to get first class in OtherClass
    Class<?> innerClass = OtherClass.class.getDeclaredClasses()[0];
    // getDeclaredConstructors for private constructor
    Constructor<?> constructor = innerClass.getDeclaredConstructors()[0];
    // to enable accessing private constructor
    constructor.setAccessible(true);
    OtherClass outerObject = new OtherClass();
    //// create instance of Test by reflection
    Object o = constructor.newInstance(outerObject);
    System.out.println(o);
}
like image 32
Ahmad Al-Kurdi Avatar answered Oct 11 '22 23:10

Ahmad Al-Kurdi