newInstance() with inner classes

2019-01-26 07:13发布

问题:

I've been working on an instantiation method that will allow me to package a variety of similar classes into one outer class. I could then instantiate each unique class type by passing the name of that type to the constructor. After a lot of research and errors, this is what I have come up with. I have left an error, to demonstrate my question.

import java.lang.reflect.Constructor;

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

        try
        {
            Class toRun = Class.forName("NewTest$" + args[0]);
            toRun.getConstructor().newInstance();
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            System.out.println(ex.getMessage());
        }

    }

    public NewTest(){}

    private class one //Does not instantiate
    {
        public one()
        {
            System.out.println("Test1");
        }
    }

    private static class two //Instantiates okay
    {
        public two()
        {
            System.out.println("Test2");
        }
    }
}

Compiling this code and running java NewTest two results in the output Test2, as I intended.

Running java NewTest one results in

java.lang.NoSuchMethodException: NewTest$one.<init>()
        at java.lang.Class.getConstructor(Unknown Source)
        at java.lang.Class.getConstructor(Unknown Source)
        at NewTest.main(NewTest.java:12)

I'm confused about this because, as far as I know, I am referencing an inner class correctly, an outer class should have access to an inner class, and I have a default no arg constructor.

回答1:

Non-static inner classes need an instance of the outer class to work properly. So, they don't "really" have a default constructor, they always have a kind of hidden parameter in which they expect an outer class instance.

I don't know why you want to have them all in a single class. If you are doing this so that it's only one file, put them in a package and in separate classes. Having less files does not make your program better.

If instead you need them to share something, so the outer class will work as a kind of "scope", you can still do that without using inner classes, but by passing them a context of some sort.

If you really really want to instantiate the inner class, you need to use the hidden constructor taking the outer class as a parameter :

NewTest outer = new NewTest();
Class<?> toRun = Class.forName("NewTest$" + args[0]);
Constructor<?> ctor = toRun.getDeclaredConstructor(NewTest.class);
ctor.newInstance(outer);


回答2:

A non-static inner class cannot be instantiated without an instance of its parent class.

new NewTest().new one()

The call above will successfully instantiate a one.

Your two is being instantiated without an outer instance, because of the static modifier. It is a static nested class.

See the difference between static nested classes and inner classes: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html



回答3:

You need to make class one static. Non-static nested classes must be instantiated with an instance of the containing class.