有时在查看代码时,我看到许多方法都指定了注释:

@SuppressWarnings("unchecked")

这是什么意思?


当前回答

在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);

和列表。的定义为。

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);

当Java编译器插入隐式强制转换时,JVM将抛出一个意外的ClassCastException。

java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer

未检查的警告告诉程序员,强制转换可能导致程序在其他地方抛出异常。使用@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;
 }

据我所知,目前它与抑制关于泛型的警告有关;泛型是一种新的编程结构,在JDK 5之前的版本中不支持,因此任何新旧结构的混合都可能导致一些意想不到的结果。

编译器会警告程序员,但是如果程序员已经知道了,他们可以使用SuppressWarnings关闭这些可怕的警告。

@SuppressWarnings注释是JDK中可用的三个内置注释之一,在Java 1.5中与@Override和@Deprecated一起添加。

@SuppressWarnings指示编译器忽略或抑制注释元素中指定的编译器警告以及该元素中的所有程序元素。 例如,如果对一个类进行了注释以抑制特定的警告,那么在该类内部的方法中生成的警告也将被分离。

您可能已经看到了@SuppressWarnings(“unchecked”)和@SuppressWarnings(“serial”),这是@SuppressWarnings注释的两个最流行的示例。前者用于抑制由于未经检查的强制转换而产生的警告,而后者用于提醒在Serializable类中添加SerialVersionUID。

阅读更多信息:https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

它是一个注释,用于禁止编译关于未检查的泛型操作(而不是异常)的警告,比如强制转换。它本质上意味着程序员不希望在编译特定代码时被通知这些他已经知道的信息。

你可以在这里阅读更多关于这个特定注释的内容:

SuppressWarnings

此外,Oracle还提供了一些关于注释用法的教程文档:

注释

正如他们所说,

“在使用泛型出现之前编写的遗留代码(在泛型这一课中讨论)时,可能会出现‘unchecked’警告。”

一种警告,编译器借此表示它不能确保类型安全。 “未经检查”的警告一词具有误导性。这并不意味着警告在任何方面都是不受限制的。术语“未检查”指的是编译器和运行时系统没有足够的类型信息来执行确保类型安全所需的所有类型检查。从这个意义上说,某些操作是“未检查”的。

“未检查”警告最常见的来源是使用原始类型。当通过原始类型变量访问对象时,会发出“unchecked”警告,因为原始类型没有提供足够的类型信息来执行所有必要的类型检查。

示例(未经检查的警告与原始类型结合):

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提供的类型信息,编译器无法判断。因此,该呼叫可能是不安全的,并发出“未检查”警告。

当编译器发现目标类型为参数化类型或类型形参的强制转换时,还会报告"unchecked"警告。

示例(未检查的警告与参数化类型或类型变量的强制转换结合在一起):

  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”警告是为了提请程序员注意强制转换的静态和动态方面之间的不匹配。

请参考:什么是“未检查”警告?