这种使用varargs安全吗?

时间:2014-08-30 16:14:17

标签: java

我有一种util方法可以将类型的varargs转换为该类型的数组 - 它看起来像这样:

public K[] array(K... ks) {
    return ks;
}

用例是这样的,不是在调用需要数组的方法时定义数组,而是简单地做数组(val1,val2,val3)。

然而,IntelliJ给了我堆污染警告。我理解这在某种程度上意味着什么,但我没有太多经验 - 所以,我想知道我是否可以添加@SafeVarargs以及这种方法是否真的安全。

IntelliJ说:

  

问题简介可能的参数化堆污染   第249行的vararg类型

     

问题解决方案最终并注释为@SafeVarargs

K被声明为类的类型参数,以及V。

2 个答案:

答案 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中,从otherMethodString[]的结果有一个隐藏的强制转换......并且在执行时失败。

如果直接从真正知道参数类型的代码中调用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");
    }
}