Общий синтаксис Java для массивов - PullRequest
15 голосов
/ 09 октября 2008

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

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

Ответы [ 6 ]

17 голосов
/ 09 октября 2008

Ответ заключается в том, что массивы могут содержать только ограниченные типы. И обобщенные классы не являются reified. То есть «тип» времени исполнения List - это просто List. Обобщения стираются во время выполнения (гугл "стена стирания" для более).

Итак, это:

List<ArrayList>[] myArray

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

List[] myArray

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

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

8 голосов
/ 09 октября 2008

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

"Предпочитаю списки массиву, потому что массивы ковариантны и дженерики инвариант '

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

List<List<ArrayList>> someListArray;

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

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

5 голосов
/ 09 октября 2008
List<ArrayList>[] someListArray;

дает вам:

array of ( List of ArrayList )

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

array of List

и произнесите его:

List<ArrayList>[] someListArray = (List<ArrayList>[]) new List[5];
0 голосов
/ 09 октября 2008

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

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

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

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

}
0 голосов
/ 09 октября 2008

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

Итак, вы сказали, что массив (объект ArrayList) является ПРАВИЛЬНЫМ.

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

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);
                }
            }
        }
    }
}
0 голосов
/ 09 октября 2008

Вы правы, говоря:

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

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

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>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...