Java Generic Arrays : Why does this compile and what does this mean?

Sarthak123 :

Java does not allow creating generic arrays directly. I understand that due to erasure generic type is not known at runtime, whereas array require type checking at runtime and hence the two are incompatible.

This piece of code does not compile -

Holder<Integer>[] integers = new Holder<Integer>[5];

Fine, but I am unsure why does this piece of code actually compile (with warning for unsafe type conversions)?

Holder<Integer>[] holders = new Holder[5];
holders[0] = new Holder<Integer>(5);
holders[1] = new Holder<Integer>(5);
holders[2] = new Holder<Integer>(5);

I don't exactly understand what did I actually trick the compiler into by removing diamond brackets. Is this an acceptable to create generic arrays?

Further, when I add this line to the code - holders[3] = new Holder<String>("Hello"); It throws a compile error Holder<String> can not be converted to Holder<Integer> I find this strange because as far as I understand the whole idea of not allowing generic arrays was because arrays could not differentiate between 2 different generic types because of the type erasure. But in this example the compiler can detect incorrect type conversions.

What am I missing here?

Sweeper :

On this page, you can see exactly why creating arrays of generic types is not allowed:

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.

stringLists should only be able to store List<String>, but by using the above code, I can not only trick the compiler, but also the runtime, into allowing me to store a ArrayList<Integer> into stringLists, due to type erasure.

but I am unsure why does this piece of code actually compile

Well, because Holder is a raw type. See What is a raw type and why shouldn't we use it?. It's perfectly fine, as far as the compiler and runtime is concerned, to create an array of a raw type, because here you are not saying that "this array can only store Holder<Integer>", you are just saying "this array can only store Holder (of anything)".

Is this an acceptable to create generic arrays?

Well, your array is technically not generic. I can assign it to a Holder[] and assign a Holder<Foo> to one of its elements, and no exception or compiler errors will occur. As far as the compiler is concerned, this is "acceptable", but because you lose type-safety, I don't recommend you use it. You should use something like ArrayList<Holder<Integer>> instead.

I find this strange because as far as I understand the whole idea of not allowing generic arrays was because arrays could not differentiate between 2 different generic types because of the type erasure. But in this example the compiler can detect incorrect type conversions.

The compiler can detect it not because the array doesn't allow you to put in Holder<String>, but because the variable's compile time type is Holder<Integer>[]. The compiler can still check the type by looking at the compile time types, but as soon as you lose the compile time type (assigning it to a variable of type Object[] or Holder[]), then it can't do it for you. The array itself allows any kind of Holder in the first place anyway, because it is a Holder[].

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=125326&siteId=1