Enum.valueOf выдает предупреждение для неизвестного типа класса, который расширяет Enum? - PullRequest
2 голосов
/ 12 августа 2011

Дайте это:

Class<? extends Enum> enumClass = ...; // being passed in from a constructor
Enum e = Enum.valueOf(enumClass, aString); // produces a warning that looks like

[непроверено] вызов непроверенного метода: valueOf (java.lang.Class, java.lang.String) в java.lang.Enum применяется к (java).lang.Class, java.lang.String)

Я не хочу использовать дженерики, потому что это серьезное изменение.Я не хочу подавлять.Я не понимаю, почему это предупреждение происходит.Я предполагаю, что это потому, что нельзя расширить тип Enum.Я понимаю.Но я не понимаю, почему подстановочный класс выдает эту странную ошибку.Есть ли способ исправить это, не используя @SupressWarning или не используя дженерики?

Редактировать : Чтобы уточнить, следующий код, использующий дженерики, удаляет предупреждение.

class Foo<T extends Enum<T>>{
    Class<T> enumClass;
    Enum e = Enum.valueOf(enumClass, aString);
}

Использование <T> - это то, что я имею в виду, используя дженерики,Я не могу этого сделать, потому что это будет огромное каскадное изменение.

Ответы [ 3 ]

4 голосов
/ 12 августа 2011

Обе Enum и Class являются общими.Поэтому, если вы не хотите никаких предупреждений:

class Foo<T extends Enum<T>>{
    Class<T> enumClass;
    T e = Enum.valueOf(enumClass, str);
}

Или у вас может быть универсальный метод:

public <T extends Enum<T>> T getEnumValue(Class<T> clazz, String name) {
    T e = Enum.valueOf(clazz, name);
    return e;
}

Но если вы не используете обобщенные типы, вы используете необработанные типыи, следовательно, компилятор выдает предупреждения - кроме подавления их нет никакой опции.

2 голосов
/ 12 августа 2011

Это похоже на ошибку компилятора - это должна быть ошибка, а не предупреждение.

При компиляции выражения вызова метода Enum.valueOf(enumClass...) сначала преобразование захвата применяется к типам аргументов.

<W extends Enum> // a new type parameter 
Class<W> enumClass; // the type of the argument after capture conversion

Затем для Enum.<T>valueOf(enumClass...) делается вывод типа, в результате получается T=W.

Затем проверьте границу T после замещения, т. Е. Является ли W подтипом Enum<W>.

(этот процесс одинаков для 15.12.2.2 и 15.12.2.3; и 15.12.2.7 определенно дает T = W)

Здесь проверка должна завершиться неудачей. Все, что знает компилятор, это то, что W является подтипом Enum, он не может сделать вывод, что W является подтипом Enum<W>. (Ну, мы знаем, что это правда, за исключением W=Enum; но это знание отсутствует в правилах подтипов, поэтому компилятор не использует его - мы можем убедиться в этом, воспроизведя этот пример с иерархией MyEnum, компилятор будет себя вести то же самое.)

Так почему же компилятор проходит проверку привязки только с предупреждением? Есть еще одно правило, которое позволяет присваивать значения от Raw до Raw<X> с предупреждением без проверки. Почему это разрешено - это другой вопрос (так не должно быть), но у компилятора есть ощущение, что Raw присваивается Raw<X>. По-видимому, это правило ошибочно смешано с вышеприведенным этапом проверки подтипа, компилятор считает, что, поскольку W равен Enum, он так или иначе является Enum<W>, компилятор проходит проверку подтипа просто с предупреждением, в нарушение спецификации. .

Если такой вызов метода не должен компилироваться, каков правильный путь? Я не вижу ничего - пока тип аргумента enumClass еще не находится в рекурсивной форме Class<X extends Enum<X>>, никакое количество приведений / преобразований не может превратить его в эту форму, поэтому нет никакого способа сопоставить подпись Enum.valueOf метода. Возможно, ребята из javac намеренно нарушили спецификацию, просто чтобы подобный код компилировался!

0 голосов
/ 12 августа 2011

Если вы подумаете о том, что должно происходить внутри valueOf, вы поймете, что ваш код не может работать так, как написано. Enum.valueOf нуждается в качестве аргумента в экземпляре фактического класса enum; затем он просто перебирает values() для этого класса в поисках совпадения.

Из-за стирания типа генерики не будут работать в вашем коде. Фактический тип не передается в Enum.valueOf.

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