Почему API Reflection создает исключение NoSuchMethodException для существующего конструктора enum? - PullRequest
0 голосов
/ 25 октября 2018

ОБНОВЛЕНИЕ : Мой вопрос не связан с Создать экземпляр класса .Этот вопрос просто должен создать экземпляр enum с одним из существующих значений.Я спрашиваю: почему API Reflection генерирует 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)

В обоих случаях результатом компиляции является класс с закрытым конструктором .Использование API отражения в Xpto.class.getDeclaredConstructor(); не сообщает об ошибке относительно факта, что Xpto является перечислением, или нет.Это просто бросает, что нет такого метода Xpto.<init>() для случая перечисления. Это не так .Потому что этот конструктор существует.

Ответы [ 3 ]

0 голосов
/ 25 октября 2018

потому что вы пытаетесь получить доступ к нестатическому внутреннему классу из статического метода, поэтому это нормально

0 голосов
/ 25 октября 2018

РЕДАКТИРОВАТЬ: Полностью изменил мой ответ после некоторых дополнительных проверок ...

Ну, ваш вывод 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);

Результат:

Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
0 голосов
/ 25 октября 2018

Вот из Java документация :

Последний метод клонирования в Enum гарантирует, что константы enum никогда не могут быть клонированы, а специальная обработка механизмом сериализации гарантирует, что дублированиеэкземпляры никогда не создаются в результате десериализации. Рефлексивное создание типов перечислений запрещено .Вместе эти четыре вещи гарантируют, что экземпляров типа enum не существует, кроме тех, которые определены константами enum.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...