Ответы:
Иногда дженерики Java просто не позволяют вам делать то, что вы хотите, и вам нужно эффективно сообщить компилятору, что то, что вы делаете, действительно будет законным во время выполнения.
Я обычно нахожу это болью, когда я издеваюсь над общим интерфейсом, но есть и другие примеры. Это, как правило , стоит попробовать разработать способ избежать предупреждения , а не подавляя её ( Java Дженерики FAQ помогает здесь) , но иногда , даже если это возможно, он изгибается код из формы , так много , что подавляя предупреждение является аккуратнее. Всегда добавляйте пояснительный комментарий в этом случае!
В этом же FAQ часто встречается несколько разделов на эту тему, начиная с «Что такое« непроверенное »предупреждение?» - это стоит прочитать.
(YourClazz<?>)
- Java никогда не предупреждает о таких приведениях, поскольку они безопасны. Однако это не всегда работает (подробности см. В разделе «Общие вопросы»).
Это аннотация для подавления предупреждений компиляции о непроверенных общих операциях (не исключениях), таких как приведение типов. По сути, это означает, что программист не хотел получать уведомления о них, о которых он уже знает, при компиляции определенного фрагмента кода.
Вы можете прочитать больше об этой конкретной аннотации здесь:
Кроме того, Oracle предоставляет учебную документацию по использованию аннотаций здесь:
Как они выразились,
«Предупреждение« непроверенное »может появляться при взаимодействии с унаследованным кодом, написанным до появления дженериков (обсуждается в уроке под названием« Обобщения »)».
Это также может означать, что текущая версия системы типов Java не подходит для вашего случая. Было несколько предложений / хаков JSR, чтобы исправить это: Типовые токены, Супер Типовые токены , Class.cast ().
Если вам действительно нужно это подавление, сузьте его как можно больше (например, не помещайте его в сам класс или в длинный метод). Пример:
public List<String> getALegacyListReversed() {
@SuppressWarnings("unchecked") List<String> list =
(List<String>)legacyLibrary.getStringList();
Collections.reverse(list);
return list;
}
SuppressWarning аннотации используются для подавления предупреждений компилятора для аннотированного элемента. В частности, unchecked
категория позволяет подавлять предупреждения компилятора, генерируемые в результате непроверенных приведений типов.
Просто: это предупреждение, с помощью которого компилятор указывает, что он не может обеспечить безопасность типов.
Метод обслуживания JPA, например:
@SuppressWarnings("unchecked")
public List<User> findAllUsers(){
Query query = entitymanager.createQuery("SELECT u FROM User u");
return (List<User>)query.getResultList();
}
Если бы я не аннотировал здесь @SuppressWarnings («unchecked»), это вызвало бы проблему со строкой, где я хочу вернуть свой ResultList.
Под ярлыком безопасность типов подразумевается: программа считается безопасной по типу, если она компилируется без ошибок и предупреждений и не вызывает никаких неожиданных исключений ClassCastException во время выполнения.
Я использую http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html
В Java дженерики реализованы посредством стирания типов. Например, следующий код.
List<String> hello = List.of("a", "b");
String example = hello.get(0);
Составлено к следующему.
List hello = List.of("a", "b");
String example = (String) hello.get(0);
И List.of
определяется как.
static <E> List<E> of(E e1, E e2);
Который после стирания типа делается.
static List of(Object e1, Object e2);
Компилятор понятия не имеет, что такое универсальные типы во время выполнения, поэтому если вы напишите что-то вроде этого.
Object list = List.of("a", "b");
List<Integer> actualList = (List<Integer>) list;
Виртуальная машина Java не имеет представления, что такое универсальные типы во время выполнения программы, поэтому она компилируется и запускается, как и для виртуальной машины Java, это приведение к List
типу (это единственное, что она может проверить, поэтому она проверяет только это).
Но теперь добавьте эту строку.
Integer hello = actualList.get(0);
И JVM выдаст неожиданное ClassCastException
, поскольку компилятор Java вставил неявное приведение.
java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer
unchecked
Предупреждение говорит программист , что отливка может вызвать программу , чтобы бросить исключение где - то в другом месте. Подавление предупреждения с помощью @SuppressWarnings("unchecked")
указывает компилятору, что программист считает, что код безопасен и не вызовет неожиданных исключений.
Почему вы хотите это сделать? Система типов Java недостаточно хороша, чтобы представлять все возможные шаблоны использования типов. Иногда вы можете знать, что приведение является безопасным, но Java не позволяет сказать об этом - можно скрыть подобные предупреждения @SupressWarnings("unchecked")
, чтобы программист мог сосредоточиться на реальных предупреждениях. Например, Optional.empty()
возвращает синглтон, чтобы избежать выделения пустых опций, которые не хранят значение.
private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
Это приведение является безопасным, так как значение, хранящееся в пустом необязательном элементе, не может быть получено, поэтому нет риска непредвиденных исключений приведения класса.
Вы можете подавить предупреждения компилятора и сообщить шаблонам, что написанный вами код является законным в соответствии с ним.
Пример:
@SuppressWarnings("unchecked")
public List<ReservationMealPlan> retreiveMealPlan() {
List<ReservationMealPlan> list=new ArrayList<ReservationMealPlan>();
TestMenuService testMenuService=new TestMenuService(em, this.selectedInstance);
list = testMenuService.getMeal(reservationMealPlan);
return list;
}
Один трюк - создать интерфейс, расширяющий базовый интерфейс ...
public interface LoadFutures extends Map<UUID, Future<LoadResult>> {}
Тогда вы можете проверить это с instanceof перед кастом ...
Object obj = context.getAttribute(FUTURES);
if (!(obj instanceof LoadFutures)) {
String format = "Servlet context attribute \"%s\" is not of type "
+ "LoadFutures. Its type is %s.";
String msg = String.format(format, FUTURES, obj.getClass());
throw new RuntimeException(msg);
}
return (LoadFutures) obj;
Насколько я знаю, сейчас это связано с подавлением предупреждений о дженериках; дженерики - это новая программная конструкция, не поддерживаемая в версиях JDK, предшествующих JDK 5, поэтому любые сочетания старых конструкций с новыми могут привести к неожиданным результатам.
Компилятор предупреждает об этом программиста, но если программист уже знает, он может отключить эти страшные предупреждения с помощью SuppressWarnings.
Предупреждение, с помощью которого компилятор указывает, что он не может обеспечить безопасность типов. Термин «непроверенное» предупреждение вводит в заблуждение. Это не значит, что предупреждение никак не проверяется. Термин «непроверенный» относится к тому факту, что компилятор и система времени выполнения не имеют достаточно информации о типе, чтобы выполнить все проверки типов, которые были бы необходимы для обеспечения безопасности типов. В этом смысле некоторые операции «не проверяются».
Наиболее распространенным источником «непроверенных» предупреждений является использование необработанных типов. «непроверенные» предупреждения выдаются при доступе к объекту через переменную необработанного типа, поскольку необработанный тип не предоставляет достаточно информации о типе для выполнения всех необходимых проверок типа.
Пример (непроверенного предупреждения в сочетании с необработанными типами):
TreeSet set = new TreeSet();
set.add("abc"); // unchecked warning
set.remove("abc");
warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.TreeSet
set.add("abc");
^
Когда вызывается метод add, компилятор не знает, безопасно ли добавлять объект String в коллекцию. Если TreeSet является коллекцией, содержащей String s (или ее супертип), то это будет безопасно. Но из информации о типе, предоставленной необработанным типом TreeSet, компилятор не может сказать. Следовательно, вызов потенциально небезопасен, и выдается предупреждение «не проверено».
«непроверенные» предупреждения также сообщаются, когда компилятор находит приведение, целевой тип которого является параметризованным типом или параметром типа.
Пример (непроверенного предупреждения в сочетании с приведением к параметризованному типу или переменной типа):
class Wrapper<T> {
private T wrapped ;
public Wrapper (T arg) {wrapped = arg;}
...
public Wrapper <T> clone() {
Wrapper<T> clon = null;
try {
clon = (Wrapper<T>) super.clone(); // unchecked warning
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
try {
Class<?> clzz = this.wrapped.getClass();
Method meth = clzz.getMethod("clone", new Class[0]);
Object dupl = meth.invoke(this.wrapped, new Object[0]);
clon.wrapped = (T) dupl; // unchecked warning
} catch (Exception e) {}
return clon;
}
}
warning: [unchecked] unchecked cast
found : java.lang.Object
required: Wrapper <T>
clon = ( Wrapper <T>)super.clone();
^
warning: [unchecked] unchecked cast
found : java.lang.Object
required: T
clon. wrapped = (T)dupl;
Приведение, целевой тип которого является параметризованным типом (конкретным или ограниченным подстановочным знаком) или параметром типа, небезопасно, если включена динамическая проверка типа во время выполнения. Во время выполнения доступно только стирание типа, а не точный статический тип, видимый в исходном коде. В результате часть выполнения приведения выполняется на основе стирания типа, а не на точном статическом типе.
В этом примере приведение к Wrapper проверит, является ли объект, возвращаемый из super.clone, оболочкой, а не оболочкой с определенным типом членов. Точно так же приведение к параметру типа T приведено к типу Object во время выполнения и, вероятно, полностью оптимизировано. Из-за стирания типа во время выполнения система не может выполнять более полезные проверки типов во время выполнения.
В некотором смысле, исходный код вводит в заблуждение, потому что он предполагает, что приведение к соответствующему целевому типу выполняется, в то время как на самом деле динамическая часть приведения проверяет только стирание типа целевого типа. Предупреждение «unchecked» выдается, чтобы привлечь внимание программиста к этому несоответствию между статическим и динамическим аспектом приведения.
Пожалуйста, обратитесь: Что такое «непроверенное» предупреждение?
Аннотация @SuppressWarnings является одной из трех встроенных аннотаций, доступных в JDK и добавленных вместе с @Override и @Deprecated в Java 1.5.
@SuppressWarnings указывает компилятору игнорировать или подавлять указанное предупреждение компилятора в аннотированном элементе и все элементы программы внутри этого элемента. Например, если класс аннотирован для подавления определенного предупреждения, то предупреждение, созданное в методе внутри этого класса, также будет разделено.
Возможно, вы видели @SuppressWarnings («непроверенный») и @SuppressWarnings («серийный»), два самых популярных примера аннотации @SuppressWarnings. Прежний используется для подавления предупреждения, генерируемого из-за непроверенного приведения, в то время как более позднее предупреждение используется для напоминания о добавлении SerialVersionUID в класс Serializable.