0

I want to implement two stacks using one array. I also want the stack implementation to be generic. Here is what I have do far:

public class TwoStack<T>
{
    private T array[];

    public TwoStack(int size)
    {
        array = new T[size];
    }

    //additional push/pop implementation
}

But the compiler throws Exception in the line inside the constructor saying "cannot create generic array.

I know that I cannot create new objects of the type T because of type erasure. But why can't I create references to objects of type T?

Swaranga Sarma
  • 12,215
  • 19
  • 54
  • 87

6 Answers6

3

A Java array actually knows its component type at runtime. As you know, a generic class, like your TwoStack<T> doesn't know anything about its generic parameter at runtime. That's why there's a conflict. T[] represents a class that knows its component type T (or subclass of T) at runtime. You therefore need to know T at runtime to create it. This is not what you want.

Some people mentioned using ArrayList<T> or such, instead of an array. Why is that? Because ArrayList<T>, like your TwoStack<T>, doesn't know or care about T at runtime, so it's a perfect match.

Can arrays still be used? Sure. (ArrayLists are implemented using arrays, so naturally anything that can be done with ArrayLists can be done with arrays.) But as we established before, T[] is not what you want.

We want something that doesn't care about T at runtime. This is Object[]. So we have to create a Object[] at runtime. Unfortunately, there is no Object[]<T> in Java, so you lose the compile-time benefits of generics. Plenty of people have created generic wrapper classes for arrays, something like Array<T>; you can easily create one too, as an exercise, but it is not present in the Java library.

If you want to use arrays, there are two options:

  1. Just use Object[], and cast to the element you want as you need it, just like it was with collections before generics. You lose all the niceties of generics, but you do it completely honestly and above-board.

  2. Lie, cheat, and cast that Object[] into a T[] (i.e. (T[])new Object[size]). Now, this immediately on the surface looks like an illegal cast. (If you, e.g. create an Object[] and cast it to a String[], you immediately get a ClassCastException, because Object[] is not a subclass of String[], though it is the other way around.) But remember that so long as you are inside your generic class, T is erased to the lowest bound, which is Object, so the Object[] to Object[] cast is okay. The danger is deferred until a later time: If you ever return this array as type T[], or allow an outside source to get a reference to this array, and you promised them that it was a T[], and those people are expecting it to be the actual type of T[] (e.g. String[]), the compiler inserts a cast, and you will get a ClassCastException. However, if you take care to never expose this array to the outside world, nobody will know about this lie of T[], and you will be able to use type-safe operations on it without casting to T.

newacct
  • 110,405
  • 27
  • 152
  • 217
1

How to create a generic array in Java?

Community
  • 1
  • 1
Eng.Fouad
  • 107,075
  • 62
  • 298
  • 390
1

It's because at runtime, there is no information about the generic types you used at compile time. Therefore the runtime cannot know whether you wanted an Object[] or a String[]. You just have to create an Object[] and cast it to T[] later.

Roland Illig
  • 37,193
  • 10
  • 75
  • 113
  • I know that because of type erasure my T[] becomes Object[] just as it happens in Collections. But the compile time check will allow me only following statements : array[0] = //instance of whatever T is substituted for. So it should be allowed, right? – Swaranga Sarma Mar 10 '11 at 20:49
  • Assigning a value to an element of a generic array works, the only thing that doesn't work is to *create* such an array. – Roland Illig Mar 10 '11 at 20:57
  • "You just have to create an Object[] and cast it to T[] later." That would be okay, until you decide to return it in a method to the outside. Then boom, it crashes. – newacct Mar 11 '11 at 07:45
  • In this case the array is some implementation detail that should be hidden anyway. No-one will ever discover this array from the outside. – Roland Illig Mar 11 '11 at 20:57
0

Java does not permit the construction of generic array without reflection or weak casting.

Johan Sjöberg
  • 43,692
  • 19
  • 120
  • 139
0

Use ArrayList instead of an [] array. It is only a tiny bit slower, and it works for this purpose, whereas Java forbids what you are trying to do.

bmargulies
  • 91,317
  • 38
  • 166
  • 290
0

Array was poor man's generics.

Java could get by just fine if it only allows Object[]. You can get by just fine if you limit yourself to Object[] only. But just like the non-generic List, using it is kind of painful. Programmer needs some other ways to remind himself what type of objects an array stores.

So Java allows you to specify the type of the elements in an array, like Number[], similar to generified List<Number>. Now javac can make sure you don't insert wrong type of elements; and you don't have to downcast an element retrieved from an array; and there's a simple covariances (for example, Interger[] is subtype of Number[])

Therefore, before the introduction of real generics, array is superior to List in APIs. It's better to return a Number[] than a raw List; the latter is hard to use for callers.

Now, with real generics, these benefits of arary are no longer relavant. Almost anywhere in implementation you needed an X[], you can use an ArrayList<X> instead; anywhere in AP you needed an X[], you can use a List<X> instead.

When you do need to use array, like when programming ArrayList<T> itself, or some other basic data structures, It is ok to use Object[] only. A generic array won't help you much, while being quite confusing itself.

irreputable
  • 42,827
  • 9
  • 59
  • 89