Почему вызов метода с общим возвратом на общий класс считается небезопасным javac?
Рассмотрим следующий код:
public class Main {
public static class NormalClass {
public Class<Integer> method() {
return Integer.class;
}
}
public static class GenericClass<T> {
public Class<Integer> method() {
return Integer.class;
}
}
public static void main(String... args) {
NormalClass safeInstance = new NormalClass();
Class<Integer> safeValue = safeInstance.method();
GenericClass unsafeInstance = new GenericClass();
Class<Integer> unsafeValue = unsafeInstance.method();
}
}
Если я скомпилирую его с помощью:
$ javac -Xlint:unchecked Main.java
Он возвращает:
Main.java:16: warning: [unchecked] unchecked conversion
Class<Integer> unsafeValue = unsafeInstance.method();
^
required: Class<Integer>
found: Class
1 warning
Обратите внимание, что только общий метод считается небезопасным, даже если на тип возвращаемого номера не указан тип общего типа.
Является ли это ошибкой javac
? Или есть более глубокая причина для этого, я не принимаю во внимание?
Ответы
Ответ 1
Сырые типы были разрешены для обеспечения совместимости с кодом, написанным до введения дженериков. Необработанные типы работают, просто игнорируя информацию типа all из всех аргументов метода и возвращаемых типов, даже информацию о типе, которая не связана с параметром типа класса. Это может привести к странным результатам, как вы уже нашли. Но это становится еще более странным, чем это. Например, это компилируется.
public class Main {
public static class GenericClass<T> {
public void foo(Class<Integer> clazz) {
}
}
public static void main(String... args) {
GenericClass unsafeInstance = new GenericClass();
unsafeInstance.foo(String.class);
}
}
Ответ 2
Тип конструктора (§8.8), метод экземпляра (§8.4, п. 9.4) или нестатического поля (§8.3) М необработанного типа С, который не унаследован от его суперклассов или суперинтерфейсов, является исходным тип, который соответствует стиранию его типа в общем объявлении, соответствующем C.
Спецификация языка Java
Ответ 3
Чтобы быть совместимым с компилятором Java 1.4, предполагается, что если вы отбросите общие аргументы в объявлении типа экземпляра, то вы будете работать со специальной версией класса, где вообще нет дженериков. И он выдает предупреждение, если вы смешиваете не общий код Java 1.4 с общим кодом Java 1.5+. Это проще, чем пытаться выяснить, действительно ли тип возвращаемого типа вашего метода не зависит от параметров. Вы всегда можете @SuppressWarning
, если вам это не нравится.
Ответ 4
Это может быть связано с созданием GenericClass, который является параметризованным типом, и, следовательно, в нем нужны аргументы типа. Предупреждение исчезает, если мы делаем что-то вроде следующего
GenericClass<String> unsafeInstance = new GenericClass<String>();
OR
GenericClass<?> unsafeInstance = new GenericClass();
В соответствии с моей точкой зрения ссылка "unsafeInstance
" относится к классу, который носит общий характер, а не "safeInstance
". Таким образом, компилятор может захотеть, чтобы информация о типе была связана с ссылкой до того, как какой-либо метод вызывается с использованием его в коде.