Java 1.6: Creating an Array of List<T>

Java 1.6: Creating an array of ListT

Well, generics tutorial give the answer to your question.

The component type of an array object
may not be a type variable or a
parameterized type, unless it is an
(unbounded) wildcard type.You can
declare array types whose element type
is a type variable or a parameterized
type, but not array objects.

This is
annoying, to be sure. This restriction
is necessary to avoid situations like:

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

If arrays of parameterized type were
allowed, the previous example would
compile without any unchecked
warnings, and yet fail at run-time.
We've had type-safety as a primary
design goal of generics.

Create ArrayList from array

new ArrayList<>(Arrays.asList(array));

Specific Java generic array creation

I don't think you can create an array of generics.
Check this out. Java 1.6: Creating an array of List<T>

This is because the type information isn't available at runtime.

How to properly define an array of linked list in Java ?

This is a proper way to create an array:

@SuppressWarnings("unchecked") LinkedList<Long> [] hashtable = new LinkedList[10];

Cannot Create Arrays of Parameterized Types

You cannot create arrays of parameterized types. For example, the following code does not compile:

List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error

The following code illustrates what happens when different types are inserted into an array:

Object[] strings = new String[2];
strings[0] = "hi"; // OK
strings[1] = 100; // An ArrayStoreException is thrown.

If you try the same thing with a generic list, there would be a problem:

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>(); // OK
stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown,
// but the runtime can't detect it.

If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.

Taken from docs.oracle.com

So what can I store in hashtable[] ?

Does it mean I am now allowed to have a linked list of string in the
hashtable[0] and a linked list of Long in hashtable1, if I do
LinkedList [] hashtable = new LinkedList[10]?

No, compiler won't allow you to store LinkedList to the hashtable array directly. Following snippet won't compile:

hashtable[0] = new LinkedList<String>();

However you can store the LinkedList without type parameters, or even a subclass of LinkedList:

@SuppressWarnings("unchecked") LinkedList<Long>[] hashtable = new LinkedList[10];

hashtable[0] = new LinkedList<Long>();
hashtable[1] = new MyLinkedList<Long>();
hashtable[2] = new LinkedList();
hashtable[3] = new MyLinkedList();

You can store the LinkedList if you cast your array to LinkedList[]. However you won't be able to store the anything else but a LinkedList:

LinkedList[] rawHashTable = hashtable;
rawHashTable[4] = new LinkedList<String>();

Object[] objectHashTable = rawHashTable;
objectHashTable[5] = "This line will throw an ArrayStoreException ";

Array of Linked Lists Java

It’s not as straightforward as it sounds, but yes, you can use java.util.LinkedList.

It requires that you declare your array an array of LinkedList or just List (not an array of String). This works:

    List<String>[] array = new List[1000];

for (int i = 0; i < array.length; i++){
array[i] = new LinkedList<>();
}

However, where I instantiate the array, I get a warning: Type safety: The expression of type List[] needs unchecked conversion to conform to List<String>[]. One would have expected new List<String>[1000] to work, but it doesn’t. It gives an error: Cannot create a generic array of List<String>. The element type of an array cannot be a generic type. It’s a peculiarity with historic reasons, we’ll just have to live with it.

Creating an array to store generic types in Java

Question 1:

Basically, this is forbidden by Java language. This is covered in Java Language Specification for generics.

When you use

ArrayList<Integer>[] pl2 = new ArrayList[10];    // warning

you get the compiler warning, because the following example will compile (generating warning for every line of code):

ArrayList wrongRawArrayList = new ArrayList();      // warning
wrongRawArrayList.add("string1"); // warning
wrongRawArrayList.add("string2"); // warning

pl2[0] = wrongRawArrayList; // warning

but now you array, that supposed to contain ArrayList of Integer, contains totally wrong ArrayList of String objects.

Question 2:

As it was already answered, declaration of p12 provides you with compile time checking and frees you from using casting when getting items from your ArrayList.

Slightly modified previous example:

ArrayList<Integer>[] pl2 = new ArrayList[10];                // warning 

ArrayList<String> wrongArrayList = new ArrayList<String>(); // OK!
wrongArrayList.add("string1"); // OK!
wrongArrayList.add("string2"); // OK!

pl2[0] = wrongArrayList; // ERROR

Now, since you are using generics, this won't compile.
But if you use

ArrayList[] pl2 = new ArrayList[10]; 

you will get the same result as in the first example.

How to create a generic array in Java?

I have to ask a question in return: is your GenSet "checked" or "unchecked"?
What does that mean?

  • Checked: strong typing. GenSet knows explicitly what type of objects it contains (i.e. its constructor was explicitly called with a Class<E> argument, and methods will throw an exception when they are passed arguments that are not of type E. See Collections.checkedCollection.

    -> in that case, you should write:

    public class GenSet<E> {

    private E[] a;

    public GenSet(Class<E> c, int s) {
    // Use Array native method to create array
    // of a type only known at run time
    @SuppressWarnings("unchecked")
    final E[] a = (E[]) Array.newInstance(c, s);
    this.a = a;
    }

    E get(int i) {
    return a[i];
    }
    }
  • Unchecked: weak typing. No type checking is actually done on any of the objects passed as argument.

    -> in that case, you should write

    public class GenSet<E> {

    private Object[] a;

    public GenSet(int s) {
    a = new Object[s];
    }

    E get(int i) {
    @SuppressWarnings("unchecked")
    final E e = (E) a[i];
    return e;
    }
    }

    Note that the component type of the array should be the erasure of the type parameter:

    public class GenSet<E extends Foo> { // E has an upper bound of Foo

    private Foo[] a; // E erases to Foo, so use Foo[]

    public GenSet(int s) {
    a = new Foo[s];
    }

    ...
    }

All of this results from a known, and deliberate, weakness of generics in Java: it was implemented using erasure, so "generic" classes don't know what type argument they were created with at run time, and therefore can not provide type-safety unless some explicit mechanism (type-checking) is implemented.



Related Topics



Leave a reply



Submit