Это похоже на ошибку компилятора - это должна быть ошибка, а не предупреждение.
При компиляции выражения вызова метода 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 намеренно нарушили спецификацию, просто чтобы подобный код компилировался!