Синтаксис Java Generics для массивов

Какую структуру данных определяет следующее объявление?

 List<ArrayList>[] myArray;

Я думаю, он должен объявить массив, где каждый элемент является List (например, LinkedList или ArrayList), и потребовать, чтобы каждый List содержал объекты ArrayList.

Мои рассуждения:

 List<String> someList;             // A List of String objects
 List<ArrayList> someList;         // A List of ArrayList objects
 List<ArrayList>[] someListArray;  // An array of List of ArrayList objects

После выполнения некоторых тестов я определил, что он принимает массив, каждый элемент которого является объектом LinkedList, и не указывает, что содержат объекты LinkedList.

Таким образом, List<ArrayList> указывает, что должен содержать List, а List<ArrayList>[] указывает, как должен быть реализован List.

Я что-то упускаю?

Вот мои тесты.

import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;


public class Generics1 {

    public static void main(String[] args) {

        List<ArrayList>[] someListArray;

        someListArray = getArrayWhereEachElementIsAnArrayListObject();
        // Why does this satisfy the declaration?
        //someListArray[0] => ArrayList object holding Strings

        someListArray= getArrayWhereEachElementIsAListOfArrayListObjects();
        //someListArray[0] => ArrayList object holding ArrayList objects

    }

    public static List[] getArrayWhereEachElementIsAnArrayListObject() {
        List[] arrayOfLists = new ArrayList[2];
        arrayOfLists[0] = getStringList();
        arrayOfLists[1] = getIntegerList();
        return arrayOfLists;
    }

  public static List[] getArrayWhereEachElementIsAListOfArrayListObjects() {   

        List list1 = new ArrayList();
        list1.add(getArrayList());

        List list2 = new ArrayList();
        list2.add(getArrayList());

        List[] arrayOfListsOfArrayLists = new ArrayList[2];
        arrayOfListsOfArrayLists[0] = list1;
        arrayOfListsOfArrayLists[1] = list2;
        return arrayOfListsOfArrayLists;
    }

    public static List getStringList() {
        List stringList= new ArrayList();
        stringList.add("one");
        stringList.add("two");
        return stringList;
    }


    public static List getIntegerList() {
        List intList= new ArrayList();
        intList.add(new Integer(1));
        intList.add(new Integer(2));
        return intList;
    }

    public static ArrayList getArrayList() {
        ArrayList arrayList = new ArrayList() ;
        return arrayList;
    }
}

Вероятно, каждому элементу было присвоено значение myArray [0] = new ArrayList <ArrayList> ();

James Schek 09.10.2008 20:49

Похоже, что все аргументы универсального типа были удалены из вашего образца кода. Это могло произойти, потому что вы заключили его в теги PRE, а сайт интерпретировал аргументы типа как искаженные или запрещенные теги HTML (согласно Q31657). Вы должны иметь возможность редактировать его.

Alan Moore 10.10.2008 07:49
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
16
2
4 947
6

Ответы 6

Джош Блох говорит:

"Prefer lists to array because arrays are covariant and generics are invariant'

Возможно, вы могли бы сделать:

List<List<ArrayList>> someListArray;

Это может привести к некоторому снижению производительности (даже не заметному, я уверен), но вы получите лучшую безопасность типов во время компиляции.

но я думаю, что вопрос должен быть больше вокруг "зачем" вам это нужно?

Мне это не «нужно». Я наткнулся на объявление во время обслуживания кода и пытался понять, что оно означает.

user19685 09.10.2008 07:47

List<ArrayList>[] someListArray;

дает вам:

array of ( List of ArrayList )

Но из-за ограничений в дженериках Java (ошибка 6229728) вы можете только создать:

array of List

и брось это:

List<ArrayList>[] someListArray = (List<ArrayList>[]) new List[5];

Вы правильно сказали:

After running some tests, I determined the declaration means an array where each element is an ArrayList object.

Выполнение этого кода

List<ArrayList>[] myArray  = new ArrayList[2];

myArray[0] = new ArrayList<String>();
myArray[0].add("test 1");

myArray[1] = new ArrayList<String>();
myArray[1].add("test 2");

print myArray;

Дает такой результат:

{["test 1"], ["test 2"]}

Мне кажется, что нет причин не делать это вместо этого:

List<ArrayList> myArray  = new ArrayList<ArrayList>();

Список - это список, способный содержать объекты ArrayList List [] - это массив таких списков

Итак, вы сказали, что массив (List of ArrayList object) ПРАВИЛЬНЫЙ.

Вы можете поделиться своими тестами. Мои собственные тесты разные

import java.util.*;

public class TestList {
    public static void main(String ... args) {
        class MySpecialLinkedList extends LinkedList<ArrayList<Integer>> {
            MySpecialLinkedList() {

            }

            public void foo() {

            }


            public Object clone()
            {
                return super.clone();
            }
        }

        List<ArrayList<Integer>> [] someListArray = new MySpecialLinkedList[10];
        for (int i = 0; i < 10; ++i) {
            someListArray[i] = new LinkedList<ArrayList<Integer>>();
            for (int j = 0; j < 20; ++j) {
                someListArray[i].add(new ArrayList<Integer>());
                for (int k = 0; k < 30; ++k) {
                    someListArray[i].get(j).add(j);
                }
            }
        }
    }
}

После дополнительных тестов я думаю, что у меня есть ответ.

List <ArrayList> [] действительно определяет массив, каждый элемент которого является списком объектов ArrayList.

Компиляция кода, показанного ниже, показала, почему мой первый тест позволил мне использовать массив, где каждый элемент представляет собой список чего угодно. Использование возвращаемых типов List [] и List в методах, заполняющих массивы, не предоставило компилятору достаточно информации, чтобы запретить присваивания. Но компилятор выдавал предупреждения о двусмысленности.

С точки зрения компилятора, метод, возвращающий List [], может возвращать List <ArrayList> (который удовлетворяет объявлению), а может и нет. Точно так же метод, возвращающий List, может возвращать или не возвращать ArrayList.

Вот результат компилятора:

javac Generics2.java -Xlint: не отмечено

Generics2.java:12: warning: [unchecked] unchecked conversion
found   : java.util.List[]
required: java.util.List<java.util.ArrayList>[]
        someListArray = getArrayWhereEachElementIsALinkedListObject();
                                                                   ^
Generics2.java:16: warning: [unchecked] unchecked conversion
found   : java.util.List[]
required: java.util.List<java.util.ArrayList>[]
        someListArray= getArrayWhereEachElementIsAListOfLinkedListObjects();

Вот мои тесты.

import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;


public class Generics2 {

    public static void main(String[] args) {

        List<ArrayList>[] someListArray;

        someListArray = getArrayWhereEachElementIsALinkedListObject();
        // Why does this satisfy the declaration?
        //someListArray[0] => LinkedList object holding Strings

        someListArray= getArrayWhereEachElementIsAListOfLinkedListObjects();
        //someListArray[0] => LinkedList object holding LinkedList objects

    }

    public static List[] getArrayWhereEachElementIsALinkedListObject() {
        List[] arrayOfLists = new LinkedList[2];
        arrayOfLists[0] = getStringLinkedListAsList();
        arrayOfLists[1] = getIntegerLinkedListAsList();
        return arrayOfLists;
    }

  public static List[] getArrayWhereEachElementIsAListOfLinkedListObjects() {

        List list1 = new LinkedList();
        list1.add(new LinkedList());

        List list2 = new LinkedList();
        list2.add(new LinkedList());

        List[] arrayOfListsOfLinkedLists = new LinkedList[2];
        arrayOfListsOfLinkedLists[0] = list1;
        arrayOfListsOfLinkedLists[1] = list2;
        return arrayOfListsOfLinkedLists;
    }

    public static List getStringLinkedListAsList() {
        List stringList= new LinkedList();
        stringList.add("one");
        stringList.add("two");
        return stringList;
    }


    public static List getIntegerLinkedListAsList() {
        List intList= new LinkedList();
        intList.add(new Integer(1));
        intList.add(new Integer(2));
        return intList;
    }

}

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

Jean 09.10.2008 14:37

Ответ в том, что массивы могут содержать только овеществленные типы. И обобщенные классы не материализуются. То есть "типом" среды выполнения List <ArrayList> является просто List. Обобщения стираются во время выполнения (подробнее см. В Google "стена стирания").

Итак, это:

List<ArrayList>[] myArray

действительно означает:

List[] myArray

Нет надежного способа объявить то, что вы пытаетесь объявить. Как правило, в этом случае я бы рекомендовал вам использовать список вместо массива. Некоторые люди зашли так далеко, что предложили рассматривать массивы как устаревшие типы теперь, когда у нас есть дженерики. Я не могу сказать, что готов зайти так далеко, но вы должны подумать, является ли коллекция лучшей альтернативой всякий раз, когда вы обращаетесь к массиву.

Книга Нафталина и Вадлера Обобщения и коллекции Java является отличным справочником по вопросам, которые могут возникнуть о дженериках. Или, конечно, Часто задаваемые вопросы по дженерикам - это ваш канонический онлайн-справочник.

Другие вопросы по теме