没有泛型的动态实例创建

时间:2010-02-06 18:17:07

标签: java

我想了解为什么以下内容不起作用:

public class HelloClass {

    private class MyClass
    {
        public MyClass() 
        {
           System.out.println ("Oh heck this is me!");   
        }
    }

    public Object newInstance (Object o)
    {
        try {
            // java.lang.InstantiationException here
            return o.getClass().newInstance();        
        } catch (Exception e) {
            e.printStackTrace(System.out);
            return null;
        }
    }

    public void run()
    {
        MyClass m = new MyClass();  
        Object o = newInstance(m);
    }

    public static void main(String[] args) 
    {
        HelloClass hd = new HelloClass();
        hd.run();
    }
}

我知道通过将newInstance参数声明为Class< T>来实现此目的的正确方法,但是想要理解为什么它不能像上面那样完成。

UPD:这是我得到的例外:

java.lang.InstantiationException: HelloClass$MyClass
    at java.lang.Class.newInstance0(Class.java:340)
    at java.lang.Class.newInstance(Class.java:308)
    at HelloClass.newInstance(HelloClass.java:14)
    at HelloClass.run(HelloClass.java:24)
    at HelloClass.main(HelloClass.java:30)

4 个答案:

答案 0 :(得分:6)

内部类的构造函数有一个隐藏的第一个参数,您需要在使用反射时提供该参数。传递外部类的实例。

而不是

return o.getClass().newInstance();

使用:

return o.getClass().getConstructor(getClass()).newInstance(this);

答案 1 :(得分:1)

问题似乎是它是一个非静态成员类,因为如果你将MyClass声明为静态并且你将它设为顶级类,它就可以工作。但不太清楚为什么会这样。

答案 2 :(得分:1)

非常好的问题!

这是因为内部类在每个构造函数中都有一个隐式参数 - 它的外部类。因此它没有默认构造函数。

要获取它的实例,必须通过将外部类作为参数传递来实例化它。

 Constructor constructor = o.getClass().getConstructor(HelloClass.class);
 return constructor.newInstance(this);

答案 3 :(得分:0)

Class对象中的newInstance方法仅适用于具有no-arg构造函数的具体类。

如果您将MyClass更改为静态,它将符合条件并且代码可以正常工作。实际上,它有一个隐式构造函数,外部对象作为参数,没有no-arg构造函数。

您可以使用构造函数的newInstance方法使您自己的newInstance方法工作:

public Object newInstance (Object o)
{
    try {
        final Constructor<? extends Object> constructor =
                     o.getClass().getConstructor(this.getClass());
        return constructor.newInstance(this);
    } catch (Exception e) {
        e.printStackTrace(System.out);
        return null;
    }
}