Подтвердить что ты не робот

Является ли это использование варгаров безопасным?

У меня есть метод утилиты для преобразования varargs типа в массив этого типа - он выглядит так:

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

Случай использования заключается в том, что вместо определения массива при вызове метода, который требует массив, вы можете просто сделать массив (val1, val2, val3).

Однако IntelliJ дает мне предупреждения о загрязнении кучи. Я понимаю, что это значит, но у меня нет большого опыта в отношении специфики, поэтому я хотел бы знать, могу ли я добавить @SafeVarargs и действительно ли этот метод безопасен.

IntelliJ говорит:

Краткое описание проблемы Возможное загрязнение кучи от параметризованного тип vararg в строке 249

Устранение неполадок Сделайте окончательный и аннотированный как @SafeVarargs

K объявляется как параметр типа класса, а также V.

4b9b3361

Ответ 1

Нет, это не безопасно - если вызвано из другого метода, который использует generics. Вот полный пример, который выглядит нормально, но выдает исключение:

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 непосредственно из кода, который действительно знает типы аргументов, то это прекрасно, потому что неявно созданный массив будет иметь правильный тип.

Ответ 2

Вы можете просто сказать своему методу, как преобразовать в соответствующий массив. Один из способов, который я нашел, - передать массив в метод с переменными, а затем скопировать на него.

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, если в массиве недостаточно места, или если есть лишнее пространство, неиспользуемые значения будут равны нулю.

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