1

Possible Duplicate:
Java how to: Generic Array creation

I want to create a Stack which contains 10 elements, I'm trying to do this with Generics. I started by creating a Stack class of Type T, but I'm getting compilation error when I try to instantiate the array of generic type.

public class Stack<T>{
    private T[] stk = new T[10];
}

What I'm doing wrong here?

Community
  • 1
  • 1
tintin
  • 4,971
  • 14
  • 57
  • 81

3 Answers3

3

You can't do this. Not without using some hacky round about code, and even then you have to do an unsafe cast in the end that completely ruins the entire reason for trying to be type safe in the first place.

This is because Java has something called type erasure, the compiler throws away all the generic information and the runtime doesn't know what T is.

Here is the preferred way of doing this:

@SuppressWarnings("unchecked")
static <T> T[] newArray(Class<T> type, int length)
{
    return (T[]) java.lang.reflect.Array.newInstance(type, length);
}

This doesn't create the throw about list instance in the naive solution of calling toArray() on a List<T> implementation hack.

For more discussion on this see

Here is an answer to a similar question about creating a type safe array at runtime.

Community
  • 1
  • 1
1

There reason you can't create a Array of a generic type is this:

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.

For instance, Box is translated to type Box, which is called the raw type — a raw type is a generic class or interface name without any type arguments. This means that you can't find out what type of Object a generic class is using at runtime. The following operations are not possible:

  public class MyClass<E> {
    public static void myMethod(Object item) {
        if (item instanceof E) {  //Compiler error
            ...
        }
        E item2 = new E();       //Compiler error
        E[] iArray = new E[10];  //Compiler error
        E obj = (E)new Object(); //Unchecked cast warning
    }
  }

http://download.oracle.com/javase/tutorial/java/generics/erasure.html

The reason to use generics is that you don't want to typecast.

That said, here are two solutions.

You can use a array of Objects and garantee you'll only push and pop T's by the methods you supply to access the array:

public class MyStack2<T>  {
Object[] myStack2;

public MyStack2() {
    myStack2 = new Object[10];
}

public void push(T t) {
    // do whatever you wanna do to push t, like myStack2[x] = t;

}

public T pop() {
    // do whatever you wanna do to pop t like return (T)myStack2[0];
            // Here we typecasted, but we can be sure that myStack2 contains only T's
            // because we garanteed it at the push method.
}

}

OR

You can use another thing other than array to store your stack.

    public class MyStack<T> {
    Stack<T> myStack;

    public MyStack() {
        myStack = new Stack<T>();
    }

    public void push(T t) {
        myStack.push(t);
    }

    public T pop() {
        return myStack.pop();
    }
}

As you can see, java already provides a Stack class so you don't have to write one, but if you really want to do it, maybe to understand how it works, you can replace the Stack class in this example by a List. With a List you'll be able to play almost the same you'd do if you were using an array.

pablosaraiva
  • 2,317
  • 1
  • 27
  • 38
1

The reason that that doesn't work is that when you write a type like String[] in Java, that means that the object knows itself at runtime that its component type is String (or a subclass thereof). Generic type parameters are not available at runtime, hence you cannot do it. We wish there was something like Object[]<T>, i.e. "an array that does not know its component type at runtime, but which has generic type checks at compile time", but such a thing does not exist in the language.

However, it appears that from your code that you intend to use this array internally, and you don't really care if the array knows T at runtime; you just need an array, period. If you don't intend to pass the array out of the class, then there are two options:

  1. Use a variable of type Object[], and create new Object[10]. This requires you to cast to T if you want to return an element from a method, which is an unchecked cast.

  2. Use a variable of type T[], and assign to it using = (T[])new Object[10]. Now people will point out that the subtyping relationship is not technically true, but so long as it's inside the class (inside the scope of T), it doesn't matter, because T is erased. So with this method you have to be extra careful never to pass or return the array reference, because you won't be warned that it's unsafe.

Both methods are the same after type erasure, and both methods will cause unchecked cast warnings, so it's really your personal preference. The second one is more convenient (you can pretend it's a T[] and get things out of it without cast), while the first one is more formally correct and safer (the second requires you to be diligent not to pass it out).

newacct
  • 110,405
  • 27
  • 152
  • 217