44

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.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
Markovian8261
  • 909
  • 4
  • 10
  • 23
  • 1
    http://www.velocityreviews.com/forums/t150488-how-to-access-private-inner-class-with-reflection.html – tckmn Jan 01 '13 at 16:42
  • To created a nested class, you must have an instance of an outer class. – Peter Lawrey Jan 01 '13 at 17:19
  • The class being private indicates you should not do this. – Raedwald May 15 '15 at 10:17
  • 1
    @PeterLawrey to be more precise, to create an `Inner` class (a non-static nested class) you need to have an instance of the outer class. To create an instance of a `Static Nested` class, you don't need an instance of the outer class. – Ray Apr 07 '18 at 19:09

3 Answers3

46

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
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • i am sorry to reply so late but what i need to do is return a class object of the class by getting the classes fully qualified name without having an instance of the outer class – Markovian8261 Jan 05 '13 at 15:13
  • @popgalop Inner classes are the same as methods. Just like you can't invoke method without object, you can't create object of inner class without object of outer class. Only exception of this rule are nested classes (just like static methods). But I suppose you can't make your inner class nested (by adding static modifier). – Pshemo Jan 05 '13 at 16:22
  • @popgalop Maybe if you tell us more about your problem we can find some better solution. – Pshemo Jan 05 '13 at 16:30
  • 1
    i am trying to write a method that will return a class with the paramater of a fully qualified name, and the class the the method returns can be any kinf of class(inner, nested) not including anonymous inner classes – Markovian8261 Jan 05 '13 at 17:07
  • @popgalop Do you mean "return *instance* of class with the parameter of a fully qualified name"? – Pshemo Jan 05 '13 at 17:24
  • well i originally meant return class object so i could create instance from it but returning an instance is fine – Markovian8261 Jan 05 '13 at 17:25
  • @popgalop To return class object you can simply use `Class.forName("your.fully.qualified.name.Of$InnerClass")`. But to create object of inner class you still need object of outer class. Maybe add to your method parameters that will be used to create instance of outer object, or add outer object instance itself. Also in case inner class have few constructors you could add parameters that specify which constructor should be used. – Pshemo Jan 05 '13 at 17:34
  • but cant you just use class.newInstance or whatever it is – Markovian8261 Jan 06 '13 at 02:14
  • @popgalop No, for at least two reasons you cant use `newInstance` on private inner class. First reason is because it invokes default constructor, and default constructor is private in private class, so you cant access it from outside of class. That is why you need to get with reflection some `Constructor` and set it accessible with `constructor.setAccessible(true);`. Second reason is as I (and other people here) told you, that you can't create inner object without outer object, so you need to place outer object as first argument in constructor but `newInstance()` doesn't have any arguments. – Pshemo Jan 06 '13 at 16:09
  • so than ill have to parse the qualified name, get an object of the outer class using that and than get the inner class from that – Markovian8261 Jan 06 '13 at 20:37
  • @popgalop Yes. Thats what you need to do. Hint: to get outer class of inner class you can use `innerClass.getDeclaringClass` or `innerClass.getEnclosingClass`. These methods works almost the same. You can read [this answer](http://stackoverflow.com/a/9360115/1393766) to see difference between them, but for your case (you said you don't want to use it on anonymous classes) they should give the same result. – Pshemo Jan 06 '13 at 23:10
  • The only problem is that if the class is a private inner class inside a private inner class is their a way to check if a class is a inner class – Markovian8261 Jan 07 '13 at 00:02
  • @popgalop Maybe if result from `getDeclaringClass()` or `getEnclosingClass` is `null` assume that this class is not inside other class. – Pshemo Jan 07 '13 at 01:55
  • i will try and see seems hard though what will i do if dont know the paramaters for an outer class encompasing the inner class – Markovian8261 Jan 07 '13 at 21:27
  • i have already the instance of the private inner class i want to access the fields of the private inner class. – Arun Pratap Singh May 15 '15 at 06:55
  • @ArunPratapSingh Check my updated answer and `getFieldValue` method. Assuming you know the name of field you want to get access to, you can do it same way as you would access private field from any other instance (get declared field, make it accessible, get value of this field stored in some instance). – Pshemo May 15 '15 at 09:45
  • @Pshemo can we use the same way to create an instance of a private nested static method? – Kasun Siyambalapitiya Sep 30 '17 at 08:34
  • 1
    @KasunSiyambalapitiya I am not sure what you mean by "create an instance of a private nested static *method*". Instance is representation of class, we can invoke methods on it, but method don't have their representations (instances). If you want to ask if we can instantiate private static class, then yes, just remember that static inner classes are similar to outer classes, so they don't need outer instance to be created so you can skip them in constructor argument. – Pshemo Sep 30 '17 at 12:07
  • @Pshemo what is the private nested class doesnot have a constructor defined in the code – Kasun Siyambalapitiya Oct 01 '17 at 09:02
  • @KasunSiyambalapitiya Then there is always the default one added by compiler (since class must always have at least one constructor). Default constructor takes no arguments (except if it is inner class, then it takes outer class instance) and have same visibility as class, so for private class it will be private constructor which means you will need to invoke `setAccessible(true)` on it if you want to use it. – Pshemo Oct 01 '17 at 09:47
18

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:

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();
        }
    }

}
Community
  • 1
  • 1
Sam
  • 7,778
  • 1
  • 23
  • 49
  • 6
    `OuterClass.InnerClass.class` will work only within `OuterClass`. We can't use `InnerClass.class` part outside of it since it is private and most probably our code will not be part of `OuterClass` (if it was reflection would not be needed). – Pshemo May 15 '15 at 09:52
  • @Pshemo `outer.new InnerClass();` would indeed do it here. When accessing the inner class with reflection from outside, one would then probably want it to implement an accessible interface for a downcast to an usable type in order to avoid the pain of invoking individual methods via reflection. However, if this is all done in own code (and not for some workarounds for third party libs, etc.), then it might be a design bug - so, not desirable at all. Similar to this example, one could 'steal' a protected member from within the same package or a subclass of the outer class, if it is not final. – Sam May 15 '15 at 11:39
1

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);
}
Ahmad Al-Kurdi
  • 2,248
  • 3
  • 23
  • 39