有时候在查看代码时,我会看到许多方法指定了一个注解:
@SuppressWarnings("unchecked")
这是什么意思?
有时候在查看代码时,我会看到许多方法指定了一个注解:
@SuppressWarnings("unchecked")
这是什么意思?
这是一种用于抑制编译警告的注释,适用于未检查的泛型操作(不包括异常),例如强制类型转换。它基本上意味着程序员不希望在编译特定代码时收到已经知道的警告信息。
关于此特定注释您可以在这里阅读更多:
此外,Oracle在这里提供了有关注释使用的教程文档:
正如他们所说,
“'unchecked'警告可能会在与早期代码(在《Java教程:泛型》中讨论)进行接口时发生。”
这也可能意味着当前的Java类型系统版本对你的情况不够好。有几个JSR提议/黑科技来修复此问题:类型令牌,超级类型令牌,Class.cast()。
如果你真的需要这种抑制,请尽量缩小范围(例如不要将其放在类本身或长方法上)。以下是一个示例:
public List<String> getALegacyListReversed() {
@SuppressWarnings("unchecked") List<String> list =
(List<String>)legacyLibrary.getStringList();
Collections.reverse(list);
return list;
}
简单来说:这是编译器发出的警告,表示它无法确保类型安全。
例如,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。
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);
当Java编译器插入隐式转换时,JVM会抛出意外的ClassCastException
异常。
java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer
unchecked
警告告诉程序员,强制类型转换可能会导致程序在其他地方抛出异常。使用@SuppressWarnings("unchecked")
来抑制警告,告诉编译器程序员相信代码是安全的,不会引发意外的异常。@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;
}
这个转换是安全的,因为空的可选项中存储的值不能被检索,所以不存在意外的类转换异常风险。
SuppressWarning注解用于禁止编译器对注解元素的警告。具体来说,unchecked
类别可以禁止由于未检查的类型转换而产生的编译器警告。
您可以抑制编译器的警告并告诉泛型,您编写的代码是合法的。
示例:
@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>> {}
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;
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");
^
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;
(YourClazz<?>)
- Java从不会对这些转换发出警告,因为它们是安全的。然而,这并不总是有效的(有关详细信息,请参见泛型常见问题解答)。 - Konrad Borowski