Ljava.lang.Object;无法转换为[Ljava.lang.Integer

时间:2014-12-21 15:56:59

标签: java generics

我编写了一个泛型类,下面是该类的构造函数。我想做这样的事情,如行

elements = (E[])new Object[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");
    }
    ArrayList<Integer> ar = new ArrayList<Integer>();
    elements = (E[])new Object[size];
}
}

有没有办法解决这些问题? E的声明是

protected E[] elements = null;    

这就是我试图打电话的方式

Random ran = new Random();
Stack<Integer> st = new Stack<Integer>();
st.push(ran.nextInt(100));

更新 伙计们,谢谢你的帮助。我正在搞乱泛型,所以问题正在形成。以下是创建问题的所有代码 -

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

更新2 : 似乎除了传递下面答案中提到的类类型之外,我们无法做到这一点。

5 个答案:

答案 0 :(得分:5)

基本上,当你做(E[])new Object[size]时,这是一个谎言。对象的实际运行时类为Object[],对于E[]来说,它不是E的子类型(除非EObject)。因此,演员在理论上是不正确的。但是,这不会立即产生任何问题,因为在Stack类中,E被删除到其上限,在本例中为Object。因此,在Stack类中,我们可以将elements用作E[],并将E放入其中并从中获取E,没有任何问题。

仅当elements类型E[]被“暴露”到类的外部(不正确)时才会出现问题,超出E的擦除范围,进入某人有E具体类型参数的范围。这通常发生在有人无意中使elements公开,或实现一种将其返回到外部的方法时

E[] getElements() {
    return elements;
}

然后在课堂外,有人有Stack<SomeSpecificType>,并调用此方法,并期望SomeSpecificType[],而不是它。

但是,您的Stack类没有这样的方法。那你怎么“暴露”elements?答案是elementsprotected,因此“暴露”到子类。在这种情况下,子类MinMaxStack使用Stack的特定类型扩展E,因此,它“看到”elements作为特定类型的数组,它不是。

答案 1 :(得分:4)

以下是重现异常所需的最小代码。

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泛型使用type erasure实现,因此在编译之后,此代码转换为以下内容:

class Stack {
    protected Object[] elements = new Object[1];
}

class IntStack extends Stack {
    void push(Integer i) {
        // throws ClassCastException
        ((Integer[])elements)[0] = i;
    }
}

显然,new Object[]不是Integer[]。注意演员如何移动到你没有明确表达的地方。这就是(E[])new Object[size]未经检查的广告并显示警告的原因。

相反,您应该使用Object[]并仅在需要将元素返回到外部世界时执行未经检查的强制转换。

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

答案 2 :(得分:3)

我认为通常的方法是将Class传递给构造函数,并使用Array.newInstance(Class<?>, int...)之类的

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

修改

在您的更新中, 请勿使用raw-types。使用Java 7及更高版本,您可以使用diamond operator <>之类的

Stack<Integer> st = new Stack<>(); 
st.push(ran.nextInt(100));

使用早期版本,您可以指定类似

的泛型类型
Stack<Integer> st = new Stack<Integer>(); 
st.push(ran.nextInt(100));

答案 3 :(得分:1)

现在很清楚了。您正在尝试创建没有通用类型的Stack。请考虑使用Stack<Integer> st = new Stack<>();

答案 4 :(得分:1)

以下是如何修复它,你不应该(T[]) new Object[DEFAULT_CAPACITY];代替抽象应该存在例如(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;
}
}