2014-12-21 4 views
3

Я написал общий класс, а ниже - конструктор класса. Я хочу сделать что-то вроде этого, как написано в строкеLjava.lang.Object; не может быть применено к [Ljava.lang.Integer

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

Есть ли способ решить такие проблемы? Декларация Е

protected E[] elements = null;  

Это, как я пытаюсь вызвать

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

Update Ребята, спасибо за помощь. Я возился с дженериками, поэтому проблема создавалась. Вот весь код, который создал проблему -

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: Кажется, кроме прохождения типа класса, как упоминалось в ответ ниже, нет никакого способа, мы можем сделать это.

+0

Как 'elements' объявлен? – lea

+0

@lea protected E [] elements = null; – Avneesh

+0

@tobias_k Даже если я это сделаю, все же основные проблемы остаются тем, что я пытаюсь решить здесь. – Avneesh

ответ

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

Спасибо за объяснение. Вот как я это сделал сейчас. – Avneesh

+0

Ему не нужно объявлять его как 'Object []' - его код как есть (с 'элементами', объявленными как' E [] '), будет отлично работать, если он сделает' elements' 'private'. – newacct

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

Edit

С вашего обновления пожалуйста не используйте 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)); 
1

теперь это ясно. Вы пытаетесь создать свой Stack без универсального типа. Вместо этого рассмотрите Stack<Integer> st = new Stack<>();.

+0

Random ran = new Random(); \t Stack st = новый Stack (); \t st.push (ran.nextInt (100)); – Avneesh

+1

Да. Когда вы пишете 'Stack st = new Stack();', java понимает его как 'Stack st = new Stack ();', он вызывает ваш 'Ljava.lang.Object; не может быть применено к ошибке [Ljava.lang.Integer]. Поэтому вам нужно указать ваш фактический тип, чтобы передать 'Integer' вместо' Object'. – Everv0id

+1

Нет. Это не исправляет проблему. – Avneesh

4

В основном, когда вы делаете (E[])new Object[size], это ложь. Фактический класс времени выполнения объекта: Object[], который не является подтипом E[] для любого E (если E не является Object). Таким образом, бросок теоретически неверен. Однако это не создает никаких проблем, поскольку внутри класса Stack, E стирается до его верхней границы, в данном случае Object. Поэтому внутри класса мы можем использовать elements как E[] и поставить E и получить E, без проблем.

Проблема возникает только тогда, когда (неправильно) тот факт, что elements является типом E[] является «разоблачил» на внешней стороне класса, вне сферы стиранием E, в сферу, где кто-то есть конкретный аргумент типа для E. Это обычно происходит, когда кто-то неосторожно делает elements общественности, или реализует метод, который возвращает его наружу, как

E[] getElements() { 
    return elements; 
} 

Затем на внешней стороне класса, кто-то имеет Stack<SomeSpecificType>, и вызвать этот метод, и ожидать SomeSpecificType[] , что не так.

Однако у вашего Stack класса нет такого метода. Итак, как вы «разоблачаете» elements? Ответ заключается в том, что elements является protected и поэтому «подвергается» подклассам. В этом случае подкласс MinMaxStack расширяет Stack с определенным типом для E, поэтому он «видит» elements как конкретный тип массива, которого он не является.

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; 
} 
} 
Смежные вопросы