我有一种util方法可以将类型的varargs转换为该类型的数组 - 它看起来像这样:
public K[] array(K... ks) {
return ks;
}
用例是这样的,不是在调用需要数组的方法时定义数组,而是简单地做数组(val1,val2,val3)。
然而,IntelliJ给了我堆污染警告。我理解这在某种程度上意味着什么,但我没有太多经验 - 所以,我想知道我是否可以添加@SafeVarargs以及这种方法是否真的安全。
IntelliJ说:
问题简介可能的参数化堆污染 第249行的vararg类型
问题解决方案最终并注释为@SafeVarargs
K被声明为类的类型参数,以及V。
答案 0 :(得分:24)
不,它不安全 - 如果从另一种使用泛型的方法调用。这是看起来的完整示例,但抛出异常:
class Utility<K> {
public K[] array(K... ks) {
return ks;
}
public K[] otherMethod(K k1, K k2) {
return array(k1, k2);
}
}
class Test {
public static void main(String[] args) throws Exception {
Utility<String> util = new Utility<String>();
// Bang!
String[] array = util.otherMethod("foo", "bar");
}
}
当编译器为otherMethod
创建字节码时,它无法创建一个正确类型的数组以传递到array
,因为它不知道类型K
。由于类型擦除,它只会使用值创建Object[]
。所以在main
中,从otherMethod
到String[]
的结果有一个隐藏的强制转换......并且在执行时失败。
如果直接从真正知道参数类型的代码中调用array
,那就没关系,因为隐式创建的数组将是正确的类型。
答案 1 :(得分:0)
您可以告诉您的方法如何转换为适当的数组。我发现的一种方法是使用变量将数组传递给方法,然后复制到它。
public K[] otherMethod(K[] parent, K k1, K k2) {
List<K> list = new ArrayList<K>();
Collections.addAll(list, array(k1, k2));
list.toArray(parent);
return parent;
}
现在输出依赖于Collections.toArray()方法,如果数组中没有足够的空间,则返回null,或者如果有额外的空间,则未使用的值将为null。
class Test {
public static void main(String[] args) throws Exception {
Utility<String> util = new Utility<String>();
String[] array = util.array("one", "two", "three");
array = util.otherMethod(array, "x", "y");
printArr(array); // prints: x y null
Utility<Integer> util2 = new Utility<Integer>();
Integer[] intarray = util2.otherMethod(new Integer[1], 1, 2);
printArr(intarray); // prints: null
Integer[] intarray = util2.otherMethod(new Integer[2], 1, 2);
printArr(intarray); // prints: 1 2
}
static void printArr(Object[] objArr) {
for (Object o:objArr) System.out.print(o+"\t");
}
}