Ljava.lang.Object; cannot be applied to [Ljava.lang.Integer
I wrote a generic class and below is a class constructor. I want to do something like this as written in the line
elements = (E[])new Object[size]
Because I don't know the generic type at runtime, so it will throw an exception.
public class Stack<E> implements IStack<E> {
protected E[] elements = null;
protected int top = -1;
protected int size= 0;
private static final int DEFAULT_CAPACITY = 10;
public Stack(){
this(DEFAULT_CAPACITY);
}
public Stack(int size){
if(size <0){
throw new IllegalArgumentException("Initial capacity cannot be negative or zero");
}
ArrayList<Integer> ar = new ArrayList<Integer>();
elements = (E[])new Object[size];
}
}
Is there a way to solve such problems? Declaration E is
protected E[] elements = null;
This is how I try to call
Random ran = new Random();
Stack<Integer> st = new Stack<Integer>();
st.push(ran.nextInt(100));
Update Guys, thanks for the help. I was messing around with generics, so the problem was creating. Here is all the code that created the problem -
public class StackMain {
public static void main(String[] args) {
MinMaxStack minMaxStack = new MinMaxStack();
Random ran = new Random();
for (int k = 0; k < 10; k++) {
minMaxStack.push(ran.nextInt(100));
}
System.out.println(minMaxStack);
}
}
public class MinMaxStack extends Stack<Integer> implements IMinMaxStack<Integer>{
private int min;
private int max;
/*
* Approach 1:
* For push method we can push and update the minimum/maximum value
* For pop method we will be traversing whole stack to find out the new minimum/maximum
*
*/
@Override
public void push(Integer element){
if(isEmpty()){
this.min = element;
this.max = element;
elements[top+1] = element;
size++;
}else{
if(element < min){
min = element;
}
if(element > max){
max = element;
}
elements[top+1] = element;
size++;
}
}
}
public class Stack<E> implements IStack<E> {
protected E[] elements = null;
protected int top = -1;
protected int size= 0;
private static final int DEFAULT_CAPACITY = 10;
public Stack(){
this(DEFAULT_CAPACITY);
}
public Stack(int size){
if(size <0){
throw new IllegalArgumentException("Initial capacity cannot be negative or zero");
}
elements = (E[])new Object[size];
}
public void push(E element) {
ensureCapacity();
elements[top+1] = element;
size++;
}
}
public interface IStack<E> {
public void push(E element );
}
public interface IMinMaxStack<E> extends IStack<E> {
public int min();
public int max();
}
Update 2 : There seems to be no way other than passing the class type as stated in the answer below.
source to share
Here is the most minimal code needed 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 not
elements[0] = i;
}
}
Java generics are implemented using the erasure type , so after compilation this code is translated 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;
}
}
It is clear that a is new Object[]
not Integer[]
. Note that the broadcast is moved to where you did not explicitly specify it. This is why (E[])new Object[size]
was unchecked and displayed a warning.
Instead, you should only use Object[]
and perform unsupervised culling when you need to return an item 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;
}
}
source to share
Basically, when you do (E[])new Object[size]
, it's a lie. The actual runtime class of the object Object[]
, which is not a subtype of E[]
any E
(if E
not Object
). So the cast is theoretically incorrect. However, this does not create any immediate problems, because the inside of the class Stack
E
is erased to its top border, in this case Object
. This way, inside the class, Stack
we can use elements
like E[]
and put E
in and get E
from it without problems.
The problem only arises when the (incorrect) fact of what elements
is a type E[]
is "exposed" to the outside of the class, outside the scope of the erasure E
, into the scope where someone has a particular type argument for E
. This usually happens when someone inadvertently makes it elements
public or implements a method that returns it outside, like
E[] getElements() {
return elements;
}
Then, outside the class, someone has Stack<SomeSpecificType>
and call that method and expect SomeSpecificType[]
, which is not what it receives.
However, your class Stack
does not have such a method. So how do you "expose" elements
? The answer lies in what elements
is protected
and therefore is "exposed" to subclasses. In this case, the subclass MinMaxStack
extends Stack
with a specific type for E
, so it "sees" elements
as a specific type of array, which it does not.
source to share
I believe the usual way is to pass Class
to a 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));
In earlier versions, you specify a generic type like
Stack<Integer> st = new Stack<Integer>();
st.push(ran.nextInt(100));
source to share
This is how you fix it, you should never do (T[]) new Object[DEFAULT_CAPACITY];
, and the 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;
}
}
source to share