为什么反射API为现有的枚举构造函数抛出NoSuchMethodException?

时间:2018-10-25 12:53:57

标签: java enums

更新:我的问题与Instantiate enum class无关。这个问题只需要使用现有值之一实例化枚举。我在问:为什么反射API会为实际存在的方法抛出NoSuchMethodException ??

以下代码是否正确运行,具体取决于Xpto被声明为class还是enum

class Xpto {
  // Bar; // include this for enum declaration
  private Xpto() {      
  }
}

public class App {
  public static void main(String[] args) throws Exception{
    Constructor<Xpto> constructor = Xpto.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    constructor.newInstance();
  }
}

在两种情况下,javap都显示一个构造函数private Xpto()。如果Xpto是一个类,那么javap -private的结果是:

class Xpto {
  private Xpto();
}

如果Xpto是一个枚举,则javap -private的结果是:

final class Xpto extends java.lang.Enum<Xpto> {
  ...
  private Xpto();
  static {};
}

对于后者,它会引发异常:

Exception in thread "main" java.lang.NoSuchMethodException: Xpto.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)

在两种情况下,编译的结果都是带有私有构造函数。在Xpto.class.getDeclaredConstructor();中使用反射API不会报告有关Xpto是枚举的事实的错误,但不是。它只是抛出一个枚举的情况,没有这样的方法Xpto.<init>()这不是真的。因为该构造函数存在。

3 个答案:

答案 0 :(得分:3)

这里来自Java documentation

  

Enum中的最终克隆方法可确保枚举常量永远不会   被克隆,并通过序列化机制进行特殊处理   确保不会由于以下原因而创建重复的实例   反序列化。 禁止以反射方式实例化枚举类型。   总之,这四件事确保没有枚举类型的实例   存在超出枚举常量定义的范围。

答案 1 :(得分:2)

编辑:经过一些其他检查后,完全改变了我的答案...

好吧,您的constructor(..., private resultListService: ResultListService) {} ... this.resultListService.resultList$ .subscribe(resultList => console.log('This is the updated resultList: ', resultList)); 的输出很奇怪,您应该验证它是否正确。我的输出是这样的:

javap -private

因此,由编译器为您的final class Xpto extends java.lang.Enum{ public static final Xpto Bar; private static final Xpto[] ENUM$VALUES; static {}; private Xpto(java.lang.String, int); // see this line! public static Xpto[] values(); public static Xpto valueOf(java.lang.String); } 真正创建的构造函数是两个参数的构造函数,采用enumString(枚举名称和值)。这是合乎逻辑的,因为在运行时所有酷枚举功能都需要名称和某种数字标识符。

因此,以这种方式更改代码会导致“更好”的错误消息:

int

结果:

Constructor<Xpto> constructor = Xpto.class.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
constructor.newInstance("Foo", 2);

答案 2 :(得分:-2)

因为您尝试从static方法访问非静态内部类,所以它是正常的