0
public class foo<T> {

    protected T[] arr;

    public foo() {
        T[] f = new T[5];
    }
}

I have two questions:

"Cannot create a generic array of T", I get this error for T[] f = new T[5];. Why can't I create a generic array?

If that's not possible, why can I declare a reference to a generic array? I don't get compilation error for the decleration: protected T[] arr;

AngryOliver
  • 357
  • 1
  • 3
  • 15

1 Answers1

0

Why can't I create a generic array?

You need to know few things:

  1. generic types are erased at runtime, so T will be compiled as Object or if <T extends SomeType> it will become SomeType,
  2. to ensure safety at runtime array needs to remembers what type of elements it can hold. In other words it remembers this

    new ElementType[size];
        ^^^^^^^^^^^
    

At runtime you can try to use different kind of references to hold some object. For instance if you have classes

abstract class Fruit{}
class Apple extends Fruit{}
class Banana extends Fruit{}

you can use

Fruit[] fruits = new Apple[10];

and because fruits is treated as array of Fruit compiler will let you write

fruits[0] = new Apple();

but also

fruits[0] = new Banana();

because fruits can hold also Banana arrays (for same reason it can hold now Apple array), but as you can see Banana is not Apple so you need mechanism which will prevent you from corrupting your array with inappropriate elements.
So while putting element to array it performs test to check if elements type is same or subtype of class used while creating array.

This mechanism wouldn't work for

T[] f = new T[5];

because at runtime this code would look like

Object[] f = new Object[5];

which would mean that array would let you store store any kind of element which seems to be too large risk so Java creators didn't let compiler accept this kind of code.


why can I declare a reference to a generic array?

For few reasons, but mostly because there is a way to create array of T type with little help of reflection.

If you use

T[] t = (T[])Array.newInstance(componentType, size);

you will create array of type componentType. componentType has to be instance of Class which represents generic T type. In other words our code can look like

class foo<T> {

    protected T[] arr;

    @SuppressWarnings("unchecked")
    public foo(Class<T> componentType) {
        arr = (T[]) Array.newInstance(componentType, 5);
    }
}

and you can use it like

foo<String> f = new foo<String>(String.class);
//                              ^^^^^^^^^^^^ class literal
Pshemo
  • 113,402
  • 22
  • 170
  • 242
  • First of all, thank you for the detailed explanation, but isn't `List` equivalently risky? – AngryOliver Jul 02 '14 at 19:10
  • @AngryOliver If you use `List` then you are explicitly saying that list can store any kind of objects (since all classes extend Object implicitly) so I don't see any problem here. If you meant to ask about `List` which would be reference to `List` then Java solved this problem by simply disallowing `List` be reference to `List`. Take a look at [`Is List a subclass of List?`](http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicitly-p) – Pshemo Jul 02 '14 at 19:37
  • But you wrote about `Object[] f = new Object[5];`: which would mean that array would let you store store any kind of element which seems to be too large risk so Java creators didn't let compiler accept this kind of code. So, why `List` isn't risky, while an array is? – AngryOliver Jul 03 '14 at 08:01
  • @AngryOliver `List` is also risky, that is why you can't use `List` as reference to `List` like you would be able to do with arrays `Object[] array = new String[5]` because arrays give you protection at runtime (they check which type can be put in there) while generic types can't (they are erased) so Java creators decided to prohibit it. `List` can be reference to only list of actual Objects `List list = new ArrayList()`, just like `List` can be reference to only list of Fruits `new ArrayList` but not `new ArrayList` – Pshemo Jul 03 '14 at 12:17
  • @AngryOliver because via `List` you would be able to add to list of Apples also Banana and this time no exception would occur while trying to put this incorrect element into list, because list in reality is backed up by array of Object which would accept any kind of elements. – Pshemo Jul 03 '14 at 12:19
  • Thank you for the detailed answer! – AngryOliver Jul 03 '14 at 13:17