Какое объяснение для следующего:
public class GenericsTest {
//statement 1
public ArrayList<Integer>[] lists;
public GenericsTest()
{
//statement 2
lists = new ArrayList<Integer>[4];
}
}
Компилятор принимает оператор 1. Оператор 2 помечается компилятором как «создание универсального массива».
Хорошее объяснение, которое я видел относительно запрета универсальных массивов, - это Вот этот, утверждающее, что, поскольку массивы ковариантны, а универсальные - нет, вы можете подорвать общую типизацию, если вы разрешите универсальные массивы.
Оставляя в стороне споры о том, должен ли язык идти на крайние меры, создавая такого рода сложную несогласованность в обращении с дженериками, чтобы вы не застрелились, как бы вы ни старались (и если кто-нибудь знает о каких-либо хороших дискуссиях по поводу родственников). достоинства / недостатки проблемы, пожалуйста, опубликуйте, мне было бы интересно увидеть аргументы), почему оператор (1) должен быть разрешен, если (2) нет?
Это потому, что вы не можете создавать, но вы можете использовать их:
public class GenericsTest {
//statement 1
public ArrayList<Integer>[] lists;
public GenericsTest()
{
//statement 2
lists = new ArrayList[4];
//statement 3
lists[0].add(new Integer(0));
//statement 4
lists[0].add(new String(""));
}
}
Утверждение 3 возможно, утверждение 4 приведет к ошибке компилятора.
На самом деле, я думаю, что поведение оператора 3 было бы неопределенным, поскольку вы не выполнили «lists [0] = new ArrayList <Integer> ();» первый...
Хм, хороший крик. Пример действительно компилируется (если вы не укажете оператор 4), но я его не запускал. Заявление 3 тогда приведет к исключению RuntimeException.
Кажется, есть неясные случаи, когда вы могли непреднамеренно вызвать ClassCastException, как описано здесь http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf (раздел 7.3)
интересное обсуждение этой темы можно найти здесь http://courses.csail.mit.edu/6.170/old-www/2006-Spring/forum/index.php%3Ftopic=324.msg1131.html
Хорошие рекомендации, спасибо. Думаю, придется пройти через все это еще немного.
В этом случае я бы не стал использовать массивы именно по этой причине. Объявление "списков" в исходном коде могло быть
List<List<Integer>> lists = new ArrayList<List<Integer>>(4);
for(int i = 0; i < 4; i++) lists.add(null); // or add an empty ArrayList<Integer>
(вы должны использовать интерфейс, а не реализацию в объявлениях переменных)
Вместо синтаксиса array [] вы должны использовать get () или set (). В остальном это эквивалент.
Итак, актуальный вопрос: почему нет ошибки при объявлении универсального массива? ?
Вы всегда будете получать ошибку, если сделаете что-то ошибочное. Добавление ошибки там, где технически проблемы нет, просто добавляет беспорядка (хотя редактор может захотеть указать вам на это).
В некоторых случаях вы можете захотеть немного изменить правила, не проверяя приведение. Нет необходимости заставлять код быть заваленным большим количеством подавлений предупреждений, чем необходимо (кроме как указать на глупость).
Оператор 4 действительно дает ошибку, но оператор 2 дает предупреждение о «неконтролируемом преобразовании», чего оно стоит.