Java 1.6: создание массива List <T>

Почему я не могу создать массив List?

List<String>[] nav = new List<String>[] { new ArrayList<String>() };

Eclipse говорит: "Невозможно создать общий массив списка"

или

ArrayList<String>[] nav = new ArrayList<String>[] { new ArrayList<String>() };

Eclipse говорит: "Невозможно создать общий массив ArrayList"

или

List<String>[] getListsOfStrings() {
    List<String> groupA = new ArrayList<String>();
    List<String> groupB = new ArrayList<String>();
    return new List<String>[] { groupA, groupB };
}

Но я могу это сделать:

List[] getLists() {
    return new List[] { new ArrayList(), new ArrayList() };
}

Eclipse говорит, что List и ArrayList являются сырыми типами, но компилируются...

Кажется довольно простым, почему он не работает?

Ответ 1

Ну, учебник generics дают ответ на ваш вопрос.

Тип компонента объекта массива не может быть переменной типа или параметризованный тип, если он не является (неограниченный). Вы можете объявлять типы массивов, тип элемента которых является переменной типа или параметризованной тип, но не массивы.

Это досадно, конечно. Это ограничение необходимо избегать таких ситуаций, как:

// Not really allowed.
List<String>[] lsa = new List<String>[10];
Object o = lsa;
Object[] oa = (Object[]) o;
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
// Unsound, but passes run time store check
oa[1] = li;

// Run-time error: ClassCastException.
String s = lsa[1].get(0);

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

Ответ 2

Обычно вы не можете создавать массивы общих типов.

Причина в том, что JVM не имеет возможности проверить, что в него помещены только правильные объекты (с помощью ArrayStoreExceptions), поскольку разница между List<String> и List<Integer> не существует во время выполнения.

Конечно, вы можете обмануть компилятор, используя необработанный тип List или несвязанный тип подстановочного символа List<?>, а затем отбросить его (с помощью непроверенного перевода) на List<String>. Но тогда вы несете ответственность за то, чтобы положить в нее только List<String> и никаких других списков.

Ответ 3

Нет точного ответа, но подсказка:

В последнем примере есть предупреждение типа raw, поскольку вы опустили типизацию списка; это, как правило, лучший (тип безопасный) подход, чтобы указать, какие типы объектов содержатся в списке, которые вы уже делали в предыдущих примерах (List<String> вместо List).

Использование массивов не рекомендуется, так как их использование содержит ошибки чаще всего; Использование классов Collection (List, Set, Map,...) позволяет использовать типизацию и удобные методы обработки их содержимого; просто взгляните на статические методы класса Collections.

Таким образом, просто используйте пример предыдущего ответа.

Ответ 4

Другим решением является расширение LinkedList<String> (или ArrayList<String> и т.д.), а затем создание массива подкласса.

private static class StringList extends LinkedList<String> {}

public static void main(String[] args)
{
    StringList[] strings = new StringList[2];
    strings[0] = new StringList();
    strings[1] = new StringList();
    strings[0].add("Test 1");
    strings[0].add("Test 2");
    strings[1].add("Test 3");
    strings[1].add("Test 4");
    System.out.println(strings[0]);
    System.out.println(strings[1]);
}