I have written a generic class and below is the constructor of the class. I want to do something like this as written in line
elements = (E[])new Object[siz
I believe the usual way is to pass the Class into the constructor, and use Array.newInstance(Class<?>, int...) like
public Stack(Class<E> cls, int size){
if(size <0){
throw new IllegalArgumentException("Initial capacity cannot be "
+ "negative or zero");
}
elements = (E[]) Array.newInstance(cls, size);
}
Edit
From your update, please don't use raw-types. With Java 7 and above you can use the diamond operator <> like
Stack<Integer> st = new Stack<>();
st.push(ran.nextInt(100));
With earlier versions you specify the generic type like
Stack<Integer> st = new Stack<Integer>();
st.push(ran.nextInt(100));
Here is the most-minimal code necessary to reproduce your exception.
class Stack<E> {
protected E[] elements = (E[])new Object[1];
}
class IntStack extends Stack<Integer> {
void push(Integer i) {
// subtly accessing elements as Integer[] which it's not
elements[0] = i;
}
}
Java generics are implemented with type erasure so after compilation, this code translates to something like this:
class Stack {
protected Object[] elements = new Object[1];
}
class IntStack extends Stack {
void push(Integer i) {
// throws ClassCastException
((Integer[])elements)[0] = i;
}
}
Clearly a new Object[] is not an Integer[]. Notice how the cast gets moved to somewhere you did not explicitly put it. This is why (E[])new Object[size] was an unchecked cast and displayed a warning.
Instead, you should use Object[] and perform the unchecked cast only when you need to return an element to the outside world.
class Stack<E> {
private Object[] elements;
private int size;
Stack(int len) {
elements = new Object[len];
}
void push(E e) {
elements[size] = e;
size++;
}
E pop() {
@SuppressWarnings("unchecked");
E e = (E)elements[size - 1];
size--;
return e;
}
}
It's clear now. You're trying to create your Stack without generic type. Consider Stack<Integer> st = new Stack<>(); instead.
Here is how you would fix it, you should not ever do (T[]) new Object[DEFAULT_CAPACITY]; instead an abstraction should be there for example (T[]) new Comparable[DEFAULT_CAPACITY];
public class ArrayStack<T extends Comparable<? super T>> implements Stack<T> {
private final int DEFAULT_CAPACITY = 50;
private int top;
private T[] elements;
@SuppressWarnings("unchecked")
public ArrayStack() {
this.elements = (T[]) new Comparable[DEFAULT_CAPACITY];
this.top = 0;
}
}
Basically, when you do (E[])new Object[size], it is a lie. The object's actual runtime class is Object[], which is not a subtype of E[] for whatever E is (unless E is Object). So the cast is, theoretically, incorrect. However, this does not create any immediate problems because inside the Stack class, E is erased to its upper bound, in this case Object. So inside the Stack class, we can use elements as E[], and put E in and get E out of it, with no problem.
A problem only occurs when the (incorrect) fact that elements is type E[] is "exposed" to the outside of the class, outside of the scope of the erasure of E, into a scope where someone has a concrete type argument for E. This usually happens when someone inadvertently makes elements public, or implements a method that returns it to the outside like
E[] getElements() {
return elements;
}
Then on the outside of the class, someone has a Stack<SomeSpecificType>, and call this method, and expect a SomeSpecificType[], which is not what it gets.
However, your Stack class does not have such a method. So how are you "exposing" elements? The answer is that elements is protected, and is therefore "exposed" to subclasses. In this case, the subclass, MinMaxStack, extends Stack with a specific type for E, therefore, it "sees" elements as a specific type of array, which it is not.