7

How can I load a class that is already on the class path, instantiate it, and also instantiate any inner classes defined within it?

EG:

public class TestClass {


    public class InnerClass { }

}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Zombies
  • 25,039
  • 43
  • 140
  • 225
  • Actually, simply doing `new TestClass();` will both load your class (if it's not already loaded) and instantiate it. Same for `new TestClass().new innerClass();`. – Pacerier Aug 25 '14 at 21:37

3 Answers3

15

Inner classes cannot exist outside the parent class. You need to construct the parent class first. Without reflection this would look like:

InnerClass innerClass = new TestClass().new InnerClass();

In reflection, you need to pass the parent class in during construction of the inner class.

Object testClass = Class.forName("com.example.TestClass").newInstance();
for (Class<?> cls : testClass.getClass().getDeclaredClasses()) {
    // You would like to exclude static nested classes 
    // since they require another approach.
    if (!Modifier.isStatic(cls.getModifiers())) {
        Object innerClass = cls
            .getDeclaredConstructor(new Class[] { testClass.getClass() })
            .newInstance(new Object[] { testClass });
    }
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • @BalusC, Why do you say that inner classes cannot exist without the parent and we need to construct the parent class first? Even though we can't instantiate an inner class without loading the outer class, we can definitely load (construct a Class instance) the inner class *before* loading the parent class: http://stackoverflow.com/questions/25458617/why-cant-an-inner-class-use-static-initializer#comment-39762439 `Class.forName("Outer$Inner");` will not implicitly load `Class.forName("Outer");` – Pacerier Aug 25 '14 at 21:32
  • @Pacerier: you're confusing nested classes with inner classes. The answer you're referring to concerns a (static) nested class. Go back to the books: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html – BalusC Aug 26 '14 at 04:56
  • @BalusC, I did not, the link I gave you is a link to the comment, not the answer. Allow me to repeat: We can definitely load the inner class before loading the outer class (and I'm not talking about nested classes). Test it yourself with the `-verbose` flag: `Class.forName("Outer$Inner");` loads the inner class without loading the outer class. In fact, we can even do `Class.forName("Outer$Inner").getMethod("M1");` without having to load the outer class. – Pacerier Aug 26 '14 at 13:10
7

As a side note, given that your primary question has been answered - often people will declare inner classes as in your example above, without giving a thought to whether they can be static inner classes instead.

In my experience, the vast majority of (non-anonymous) inner classes can be static, as they don't need to access their parent class' instance members. Declaring the inner class as static in this case is both more efficient (as the runtime doesn't need to define a new class for each parent instance), less confusing (since new TestClass().new InnerClass().getClass() != new TestClass().new InnerClass().getClass()) and easier to instantiate if you don't have an appropriate instance of TestClass handy.

So if this applies to you, you could (and arguably should) declare you inner class thusly:

public class TestClass {

    public static class InnerClass { }

}

and then you can simply instantiate it as new TestClass.InnerClass().

(If you need to access member fields from within InnerClass, then just ignore all this of course!)

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
  • 2
    Yeah, just like `final` variables, it arguably *should* be the default at the language level - so instead one needs to make it the default on a habitual level. – Andrzej Doyle May 19 '10 at 20:45
  • I agree. But then again, so do most people who have at some point experienced a functional programming language. – Gerco Dries May 19 '10 at 21:01
  • The runtime does not "need to define a new class for each parent instance". There is only one definition (byte-code) of the inner class, even if it is not static. The one major difference between an inner class and a nested class (i.e. one with `static`) is the implicit definition of the parent class reference variable that the compiler automatically generates in the inner class. I agree with you about favoring nested classes over inner classes. – Kevin Brock May 20 '10 at 04:59
2
Class.forName("your classname").newInstance().

The inner classes will be instantiated only if the constructor instantiates them.

MattAllegro
  • 6,455
  • 5
  • 45
  • 52
Justin
  • 4,437
  • 6
  • 32
  • 52