Thursday, March 24, 2011

Java generics and array initialization

What's the explanation for the following:

public class GenericsTest {
    //statement 1
    public ArrayList<Integer>[] lists;

    public GenericsTest()
    {
            //statement 2
     lists = new ArrayList<Integer>[4];
    }
}

The compiler accepts statement 1. Statement 2 is flagged by the compiler for "generic array creation".

A good explanation I've seen regarding disallowing generic arrays is this one, arguing that since arrays are covariant and generics are not you could subvert the generic typing if you allowed generic arrays.

Leaving aside the argument over whether the language should go to the extreme lengths of creating this kind of complicated inconsistency in the treatment of generics to keep you from shooting yourself no matter how hard you try (and if anyone knows of any good discussions on the relative merits/demerits of the issue please post, I'd be interested to see the arguments), why should statement (1) be allowed if (2) isn't?

From stackoverflow
  • It's because you can't create, but you can use them:

    public class GenericsTest {
        //statement 1
        public ArrayList<Integer>[] lists;
    
        public GenericsTest()
        {
            //statement 2
            lists = new ArrayList[4];
            //statement 3
            lists[0].add(new Integer(0));
            //statement 4
            lists[0].add(new String(""));
        }
    }
    

    Statement 3 is possible, statement 4 will lead to a compiler error.

    nsayer : Statement 4 does indeed give an error, but statement 2 gives an "unchecked conversion" warning, for what it's worth.
    Evan : Actually, I think the behaviour of statement 3 would be indeterminate, as you haven't done a "lists[0] = new ArrayList();" first...
    Sven Lilienthal : Hm, good shout. The example actually compiles (if you leave out statement 4) but I haven't run it. Statement 3 would then lead to a RuntimeException.
  • There seems to be obscure cases where you could inadvertently cause a ClassCastException as explained here http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf (section 7.3)

    an intersting discussion on this topic could be found here http://courses.csail.mit.edu/6.170/old-www/2006-Spring/forum/index.php%3Ftopic=324.msg1131.html

    Steve B. : Good references, thanks. Going to have to go through all this a bit more, I think.
  • In this case, I would avoid using arrays for just this reason. The declaration of "lists" in your original code could be

    List<List<Integer>> lists = new ArrayList<List<Integer>>(4);
    for(int i = 0; i < 4; i++) lists.add(null); // or add an empty ArrayList<Integer>
    

    (you should use the interface rather than the implementation in variable declarations)

    Instead of array [] syntax, you would use get() or set(). Other than that, it's equivalent.

  • This is explained pretty well in Effective Java (second edition), Item 25 - "Prefer lists to arrays". It's a book I can highly recommend!

    Effective Java

  • So the actual question is: Why is there no error for declaring a generic array? ?

    You will always get an error at the point you do something erroneous. Adding an error where there isn't technically a problem just adds to a clutter (although an editor might want to point that out to you).

    In some circumstances you may want to bend the rules a bit with an unchecked cast. There's no need to force the code to be littered with more warning suppressions than necessary (other than to point out the folly).

0 comments:

Post a Comment