转载自:http://softlab.sdut.edu.cn/blog/subaochen/2017/04/safevarargs%E7%9A%84%E7%94%A8%E6%B3%95/
@SafeVarargs在JDK 7中引入,主要目的是处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。可变长参数是使用数组存储的,
而数组和泛型不能很好的混合使用[effective-java, p105,第25条:列表优先于数组]
1、
,因此当在可变长参数中使用泛型时,编译器都会给出警告信息。考虑#[java-7-new-feature-cookbook, p35]
package cn.edu.sdut.softlab.safevarargs; import java.util.ArrayList; /** * Created by subaochen on 17-4-3. */ public class SafeVarargsTest { public static void main(String[] args) { ArrayList<Integer> a1 = new ArrayList<>(); a1.add(new Integer(1)); a1.add(2); showArgs(a1, 12); } //@SafeVarargs public static <T> void showArgs(T... array) { for (T arg : array) { System.out.println(arg.getClass().getName() + ":" + arg); } } }
2、
开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题,否则可能导致运行时的类型转换异常。下面给出一个“堆污染”的实例,参见1。
package cn.edu.sdut.softlab.safevarargs; import java.util.Arrays; import java.util.List; /** * Created by subaochen on 17-4-3. * 本例取自SafeVarargs的javadoc文档 */ public class UnsafeMethodTest { public static void main(String[] args) { List<String> list1 = Arrays.asList("one", "two"); List<String> list2 = Arrays.asList("three","four"); unsafeMethod(list1, list2); } @SafeVarargs // 其实并不安全! static void unsafeMethod(List<String>... stringLists) { Object[] array = stringLists; List<Integer> tmpList = Arrays.asList(42, 56); array[0] = tmpList; // tmpList是一个List对象(类型已经擦除),赋值给Object类型的对象是允许的(向上塑型),能够编译通过 String s = stringLists[0].get(0); // 运行时抛出ClassCastException! } }
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
对这个结果意外吗?我们来详细分析一下。在1中,当代码执行到第22行时的状态如1所示,数组array和stringLists同时指向了参数数组,tmpList是一个包含两个Integer对象的list对象。
3、
array[0] = tmpList;
时,几个变量的关系如2所示,虚线表示原先的指向关系,实线表示新的指向关系。此时,参数数组的第0个元素指向了包含两个Integer对象的list对象tmpList。当进一步执行:
String s = stringLists[0].get(0);