Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer

前端 未结 5 1516
[愿得一人]
[愿得一人] 2020-12-29 17:06

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         


        
相关标签:
5条回答
  • 2020-12-29 17:37

    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));
    
    0 讨论(0)
  • 2020-12-29 17:38

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-29 17:39

    It's clear now. You're trying to create your Stack without generic type. Consider Stack<Integer> st = new Stack<>(); instead.

    0 讨论(0)
  • 2020-12-29 17:55

    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;
    }
    }
    
    0 讨论(0)
  • 2020-12-29 17:57

    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.

    0 讨论(0)
提交回复
热议问题