Java не відмічена: неперевірене створення загального масиву для параметра varargs


112

Я встановив Netbeans відображати неперевірені попередження в моєму коді Java, але я не можу зрозуміти помилку в наступних рядках:

private List<String> cocNumbers;
private List<String> vatNumbers;
private List<String> ibans;
private List<String> banks;
...
List<List<String>> combinations = Utils.createCombinations(cocNumbers, vatNumbers, ibans);

Дає:

[unchecked] unchecked generic array creation for varargs parameter of type List<String>[]

Джерело методу:

/**
 * Returns a list of all possible combinations of the entered array of lists.
 *
 * Example: [["A", "B"], ["0", "1", "2"]]
 * Returns: [["A", "0"], ["A", "1"], ["A", "2"], ["B", "0"], ["B", "1"], ["B", "2"]]
 *
 * @param <T> The type parameter
 * @param elements An array of lists
 * @return All possible combinations of the entered lists
 */
public static <T> List<List<T>> createCombinations(List<T>... elements) {
    List<List<T>> returnLists = new ArrayList<>();

    int[] indices = new int[elements.length];
    for (int i = 0; i < indices.length; i++) {
        indices[i] = 0;
    }

    returnLists.add(generateCombination(indices, elements));
    while (returnLists.size() < countCombinations(elements)) {
        gotoNextIndex(indices, elements);
        returnLists.add(generateCombination(indices, elements));
    }

    return returnLists;
}

Що саме не так

Забув згадати, але я використовую Java 7.

Правка : Також зараз я бачу, що метод має таке:

[unchecked] Possible heap pollution from parameterized vararg type List<T>
  where T is a type-variable:
    T extends Object declared in method <T>createCombinations(List<T>...)

17
Що б ви не робили, у Java вам не потрібно ініціалізувати новостворений масив int з 0s ...
Thomas Mueller

1
@ThomasMueller Хороший лов там
skiwi

Відповіді:


165

Як згадувалося вище janoh.janoh, varargs на Java - це лише синтаксичний цукор для масивів плюс неявне створення масиву на викличному сайті. Так

List<List<String>> combinations =
    Utils.createCombinations(cocNumbers, vatNumbers, ibans);

насправді

List<List<String>> combinations =
    Utils.createCombinations(new List<String>[]{cocNumbers, vatNumbers, ibans});

Але, як ви можете знати, new List<String>[]заборонено в Java з причин, які були висвітлені в багатьох інших питаннях, але в основному це стосується того, що масиви знають тип їх компонента під час виконання, і перевіряють, чи додані елементи відповідають його компоненту тип, але ця перевірка неможлива для параметризованих типів.

У будь-якому випадку, компілятор, а не збої, створює масив. Це робить щось подібне до цього:

List<List<String>> combinations =
    Utils.createCombinations((List<String>[])new List<?>[]{cocNumbers, vatNumbers, ibans});

Це потенційно небезпечно, але не обов'язково небезпечно. Більшість методів varargs просто перебирають елементи varargs та читають їх. У цьому випадку це не хвилює тип виконання масиву. Це справа з вашим методом. Оскільки ви перебуваєте на Java 7, вам слід додати @SafeVarargsпримітку до свого методу, і ви більше не отримуватимете це попередження. В основному ця анотація говорить, що цей метод піклується лише про типи елементів, а не про тип масиву.

Однак є деякі методи varargs, які використовують тип виконання масиву. У цьому випадку це потенційно небезпечно. Тому попередження є.


16
Дякуємо, що не тільки згадали про SafeVarags, але і за те, що нам сказали, коли ми можемо ним користуватися.
KitsuneYMG

12
Якщо це не було очевидно для когось (як це не було для мене), у Javadocs для @SafeVarargsє приклад методу, який є небезпечним docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig

3
Тож @SafeVarargsможе бути використаний, коли ваш метод споживає лише елементи масиву і не створює (і ніколи) елементів, які потрібно поставити в масив? Слід бути особливо обережним, якщо ви призначаєте аргумент масиву для поля, яке може бути маніпульовано іншими методами, оскільки визначення того, що на ньому не виконуються небезпечні операції, може бути нетривіальним.
neXus

13

Оскільки компілятор java використовує неявне створення масиву для varargs, а java не дозволяє створювати загальний масив (тому що аргумент типу не піддається повторенню).

Нижче наведено правильний код (ці операції дозволені з масивами), тому потрібне неперевірене попередження:

public static <T> List<List<T>> createCombinations(List<T> ... lists) {
    ((Object[]) lists)[0] = new ArrayList<Integer>();
    // place your code here
}

Дивіться вичерпне пояснення тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.