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

Java 为什么反射API为现有枚举构造函数抛出NoSuchMethodException?,java,enums,Java,Enums,更新:我的问题与此无关。这个问题只需要用一个现有值实例化枚举。我在问:为什么反射API为一个真正存在的方法抛出NoSuchMethodException 根据Xpto是声明为class还是enum,以下代码运行时是否没有错误 class Xpto { // Bar; // include this for enum declaration private Xpto() { } } public class App { public static void main(

更新:我的问题与此无关。这个问题只需要用一个现有值实例化枚举。我在问:为什么反射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();
  }
}
如果
Xpto
是一个枚举,那么
javap-private的结果是:

class Xpto {
  private Xpto();
}
final class Xpto extends java.lang.Enum<Xpto> {
  ...
  private Xpto();
  static {};
}
final类Xpto扩展java.lang.Enum{
...
私有Xpto();
静态{};
}
但对于后者,它抛出了一个例外:

Exception in thread "main" java.lang.NoSuchMethodException: Xpto.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
线程“main”java.lang.NoSuchMethodException中的异常:Xpto.() 位于java.lang.Class.getConstructor0(未知源)
在这两种情况下,编译的结果都是一个带有私有构造函数的类。在
Xpto.class.getDeclaredConstructor()中使用反射API
不报告有关
Xpto
是枚举这一事实的错误,而不是。它只是抛出,对于枚举,没有这样的方法
Xpto。
这不是真的。因为该构造函数存在。

这里是来自Java的:

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


因为您试图从静态方法访问非静态的内部类,所以它的正常编辑:在一些额外的检查之后完全更改了我的答案

嗯,您的
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);
}
因此,编译器为
enum
创建的构造函数实际上是一个双参数构造函数,包含
String
int
(enum名称和值)。这是合乎逻辑的,因为在运行时,所有酷枚举特性都需要一个名称和某种数字标识符

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

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

那为什么要使用枚举?我不是该枚举的提供者。但我需要一个不同的内部值。可能重复“需要用新值实例化的枚举类型定义”。再次。。。那是不可能的。它描述了如何向
enum
添加一个新值。我没有看到来自javap的构造函数,只看到了参数less。这里是我的javap输出:。我正在使用JDK11。不过,我已经用JDK 8编译了它,并得到了相同的输出。@MiguelGamboa-hmm,这很奇怪。就我而言,这都是Oracle Java 8。也许JDK 11的javap实现中有一些变化,现在它计算回代码中的构造函数(删除两个自动参数)?但这也会很奇怪。。。可能是一个新问题的基础:-)你在哪里找到一个内部类?
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)