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.

+3


source to share


5 answers


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;
    }
}

      

+4


source


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.

+4


source


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));

      

+3


source


It is now clear. You are trying to create yours Stack

without a generic type. Consider instead Stack<Integer> st = new Stack<>();

.

+1


source


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;
}
}

      

+1


source







All Articles