当前位置: 首页 > 知识库问答 >
问题:

使用反射实例化内部类时的InstantiationException。为什么?

拓拔俊艾
2023-03-14

我不能创建B-Object,但为什么呢?

public class AFactory {

    public int currentRange;

    private abstract class A {
        protected final Object range = currentRange;

        public int congreteRange = 28;
    }

    public class B extends A {
        public int congreteRange = 42;
    }

    synchronized A createNew(Class<? extends A> clazz) throws Exception {
        // EDIT: there is accessible default constructor
        currentRange = clazz.newInstance().congreteRange;
        return clazz.newInstance();
    }

    public static void main(String[] args) throws Exception {
        AFactory factory = new AFactory();
        System.out.println(factory.createNew(B.class).range);
    }
}

例外情况是:

Exception in thread "main" java.lang.InstantiationException: AFactory$B
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:325)
at AFactory.createNew(AFactory.java:15)
at AFactory.main(AFactory.java:21)

共有1个答案

葛高澹
2023-03-14

问题是您试图实例化一个内部类,而这个内部类只能在外部类的实例上访问。内部类的构造函数采用封闭类的隐式隐藏实例。通过分析这个简单类的字节代码可以看到:

public class Demo {
    class Test {
    }
}

现在,编译代码:

javac Demo.java

这将创建两个类文件:

Demo.class
Demo$Test.class
javap -c . Demo$Test
class Demo$Test {
  final Demo this$0;   

  Demo$Test(Demo);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:LDemo;
       5: aload_0
       6: invokespecial #2                  // Method java/lang/Object."<init>":
()V
       9: return
}

那么,你看到类的构造函数了吗?它以demo为参数。所以,没有0-arg构造函数。

但是,如果您使内部类静态化,它就会起作用,因为这样您就不需要任何封闭类的实例来调用内部类构造函数。

使用静态内部类-替代选项:

public class AFactory {

    public static int currentRange;

    private static abstract class A {
        protected final Object range = AFactory.currentRange;
    }

    public static class B extends A {
        public int congreteRange = 42;
    }

    synchronized A createNew(Class<? extends B> clazz) throws Exception {
        currentRange = clazz.newInstance().congreteRange;
        return clazz.newInstance();
    }

    public static void main(String[] args) throws Exception {
        AFactory factory = new AFactory();
        System.out.println(factory.createNew(B.class).range);
    }
}
public class AFactory {

    public int currentRange;

    private abstract class A {
        protected final Object range = currentRange;
    }

    public class B extends A {
        public int congreteRange = 42;
    }

    synchronized A createNew(Constructor<? extends A> ctor) throws Exception {
        // Pass `this` as argument to constructor. 
        // `this` is reference to current enclosing instance
        return ctor.newInstance(this); 
    }

    public static void main(String[] args) throws Exception {
        AFactory factory = new AFactory();

        // Get constructor of the class with `AFactory` as parameter
        Class<B> bClazz = B.class;
        Constructor<B> ctor = bClazz.getDeclaredConstructor(AFactory.class);

        System.out.println(factory.createNew(ctor));
    }
}
 类似资料:
  • 问题内容: 是否可以使用Java反射从另一个类实例化私有内部类。例如,如果我采用了这段代码 是否可以实例化并从main类中的main方法获得对Test的访问。 问题答案: 使用反射时,您会发现该内部类的构造函数将外部类的实例作为附加参数(总是第一个)。 例:

  • 是否可以从类main中的main方法实例化并获得对Test的访问。

  • 我尝试实例化以下Java代码中定义的内部类: 我得到了这个例外: 我错过了什么?

  • 问题内容: 我有一个实用程序方法,当从中删除了不相关的逻辑时,简化的方法将如下所示: 问题是,如果是诸如的内部类,则该方法即使是公共方法也将不起作用,因为它将抛出。 有没有办法动态实例化内部类? 问题答案: 如果它是真正的 内部 类而不是 嵌套 (静态)类,则有一个隐式构造函数参数,它是对外部类实例的引用。在那个阶段您不能使用- 必须获得适当的构造函数。这是一个例子:

  • 问题内容: 假设您有一个文本文件,例如: 您希望相应地更新相应的对象: 凡是不同种类的枚举。 我想有一个通用的方法来实例化枚举值。也就是说,在运行时使用反射,而无需事先知道对象的枚举类型。 我会想到这样的事情: 问题是:应该有什么呢?给定其String表示形式,甚至可以实例化未知枚举吗? 问题答案: 之后不应该被调用-它返回实例的类 你可以投,避免一般性的问题,因为你已经知道的是

  • 本文向大家介绍PHP的反射类ReflectionClass、ReflectionMethod使用实例,包括了PHP的反射类ReflectionClass、ReflectionMethod使用实例的使用技巧和注意事项,需要的朋友参考一下 PHP5 具有完整的反射API,添加对类、接口、函数、方法和扩展进行反向工程的能力。 反射是什么? 它是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类