Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I allowed to declare a generic array as an instance variable?

I am fully aware that generic arrays cannot be instantiated like such:

data = new Entry<K, V>[];

This will result in an error:

Cannot create a generic array of Entry<K,V>

So, why am I allowed to declare an instance variable that is a generic type array with no errors?

private Entry<K, V>[] data;
like image 729
grimetime Avatar asked Mar 12 '12 07:03

grimetime


2 Answers

In principle, the comment of Joachim Sauer is already your answer, however, I would like to detail it a bit.

Sun (Oracle) knows of a phenomenon called memory-pollution, which always happens if a generic variable pointer points to a type-incompatible object. This can be enforced for example with the following code:

List<String> list = new ArrayList<String>();
List<Number> numberList = (List<Number>)(List)list;

obviously, you will start seeing ClassCastExceptions, once you start working with that code. This was perfectly ok for Sun when designing Generics, because you get an obligatory warning RawType/Unchecked conversion. Whenever this warning is issued, you know, that you have code, which is not 100% type-checked and memory pollution may occur.

The overall design principle in Generics is, that all possible memory-pollutions are indicated by such warnings. This is why the creation of generic arrays is forbidden. Assuming it was not, here is what could happen:

List<String>[] array = new List<String>[5];
Object[] oArray = array // this works without warning and has to for compatibility
List<Object> oList = new ArrayList<Object>();
oArray[1] = oList;

You will have memory-pollution there without any warning and for compatibility reasons, a warning cannot be generated. This is why Sun decided to forbid arrays of generic types. However variables might be declared because you get your unchecked conversion warning there and this is all Sun wanted: a warning if pollution could occur.

like image 107
Jonathan Avatar answered Oct 06 '22 00:10

Jonathan


Because the compiler and / or JIT needs to be able to infer the generic types.

When you try to create an instance of Entry<K, V>[] the compiler can't infer the types K and V, and so you wouldn't be able to create the actual object (which means that the compiler can't find the right constructor).

But, if you have a member of type Entry<K, V>[] it's just a reference to some generic type.
The right type will be inferred when it's used, according to the actual type that will be assigned to it. And because it references an actual type, all the method calling anc constructors will be decided by the type referenced.

like image 27
Yochai Timmer Avatar answered Oct 06 '22 00:10

Yochai Timmer