Ответ 1
Интересно, это тонкое изменение в обработке необработанных типов.
Во-первых, давайте проясним ваш пример. Тип возврата Object.getClass
является особенным:
Фактический тип результата
Class<? extends |X|>
, где|X|
- это стирание статического типа выражения, на которое вызываетсяgetClass
.
В этом случае X
будет параметром типа C
, который стирает до Enum
. Итак sampleCol.getClass()
возвращает Class<? extends Enum>
. EnumSet.allOf
объявляет параметр типа E extends Enum<E>
, а в вашем случае ? extends Enum
выводится как его аргумент типа.
Важная часть состоит в том, что Enum
является сырым типом. Было замечено, что использование типов raw стирает, по-видимому, несвязанные дженерики, например, на этом посту: Почему этот общий код Java не компилируется? В своем ответе там Джон Skeet цитирует JLS §4.8 ( "Необработанные типы" ), чтобы покрыть это неинтуитивное поведение.
Подобное поведение, по-видимому, происходит в вашем примере с Java 7: EnumSet.allOf(sampleCol.getClass())
разрешено компилировать с предупреждением "unchecked invocation" (это скрывается при последующем предупреждении "непроверенного преобразования" о назначении полученного raw EnumSet
до Set<C>
).
Возникает вопрос: должно ли возникновение необработанного типа в общих подстановочных границах разрешать непроверенные преобразования? JLS §4.8 не упоминает об этом, поэтому он неоднозначен. Возможно, это ошибка, но это похоже на разумное ужесточение этого поведения. Хотя стандартного типа raw, такого как Enum
, можно было бы ожидать от устаревших API, "наполовину испеченный" тип, такой как Class<? extends Enum>
, мог появляться только после генерики, и поэтому на самом деле не имеет смысла позволять ему нарушать проверку общего типа.
В любом случае мне интересно узнать, может ли кто-нибудь указать на документацию об этом изменении - мой поиск ничего не изменил.
О вашем конкретном коде: вы должны использовать getDeclaringClass()
. Компилятор не может знать, что вызов getClass
на C
будет возвращать точно Class<C>
; на самом деле, он не будет использоваться в перечислении с классом постоянной определенности. Это именно тот прецедент, для которого Enum
объявляет этот метод.