views:

1952

answers:

6

What data structure does the following declaration specify?

 List<ArrayList>[] myArray;

I think it should declare an array where each element is a List (e.g., a LinkedList or an ArrayList) and require that each List contain ArrayList objects.

My reasoning:

 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

After running some tests, I determined that it accepts an array where each element is an LinkedList object and does not specify what the LinkedList objects contain.

So List<ArrayList> specifies what the List must contain, but List<ArrayList>[] specifies how the List must be implemented.

Am I missing something?

Here are my tests.

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;
    }
}
+7  A: 

Mr Josh Bloch says:

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

You could perhaps do:

List<List<ArrayList>> someListArray;

This may give some performance hit (not even noticable i bet) but you will get better type safety at compile time.

but I think the question should be more around "why" you need this?

Mark
I don't "need" this. I ran across the declaration during code maintenance and was trying to understand what the declaration meant.
Ok thats cool, I was just checking...
Mark
+5  A: 

List[] someListArray;

gives you an:

array of ( List of ArrayList )

But due to limitations in Java generics (bug 6229728) you can only actually create:

array of List

and cast it:

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

You are correct in saying:

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

Executing this code

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;

Produces this result:

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

It seems to me there is no reason not to do this instead:

List<ArrayList> myArray  = new ArrayList<ArrayList>();
Abarax
A: 

List is a List capable of holding ArrayList objects List [] is an array of such Lists

So, what you said is that An Array of (List of ArrayList object) is CORRECT.

Can you share what your tests were. My own tests are different

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);
                }
            }
        }
    }
}
anjanb
A: 

After running some additional tests, I think I have my answer.

List<ArrayList>[] does indeed specify an array where each element is a List of ArrayList objects.

Compiling the code as shown below revealed why my first test allowed me to use an array where each element is a List of anything. Using return types of List[] and List in the methods that populate the arrays did not provide the compiler enough information to prohibit the assignments. But the compiler did issue warnings about the ambiguity.

From the compiler's point of view, a method returning a List[] might be returning a List<ArrayList> (which satisfies the declaration) or it might not. Similarly, a method returning a List might or might not return an ArrayList.

Here was the compiler output:

javac Generics2.java -Xlint:unchecked

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();

Here are my tests.

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

}
you should be able to edit your original post to include the above code which would be better than posting it as an answer
Jean
+12  A: 

The answer is that arrays can only hold reified types. And generified classes are not reified. That is, the runtime "type" of the List<ArrayList> is just List. Generics are erased at runtime (google "wall of erasure" for more).

So this:

List<ArrayList>[] myArray

really means:

List[] myArray

There is no type-safe way to declare what you're trying to declare. Generally, I'd recommend you use a List instead of an array in this case. Some people have gone so far as to suggest that arrays should be treated as deprecated types now that we have generics. I can't say I'm willing to go that far but you should consider whether a collection is a better alternative whenever you're drawn to an array.

The book Java Generics and Collections by Naftalin and Wadler is an excellent reference for questions you might have about generics. Or, of course, the Generics FAQ is your canonical online reference.

Alex Miller