2010-04-17 11 views
5
interface Addable<E> { 
    public E add(E x); 
    public E sub(E y); 
    public E zero(); 
} 

class SumSet<E extends Addable> implements Set<E> { 

    private E element; 

    public SumSet(E element) { 
     this.element = element; 
    } 

    public E getSum() { 
     return element.add(element.zero()); 
    } 
} 

Parece que element.add() no devuelve un E extends Addable sino un Object. ¿Porqué es eso? ¿Tiene algo que ver con que Java no sepa en tiempo de ejecución cuáles son realmente los tipos de objetos, por lo que simplemente asume que son Objetos (por lo tanto, requieren un molde)?¿Cuál es el problema con este código de Java que trata con Generics?

Gracias

+2

+1 para publicar un fragmento de código que se puede cortar y pegar fácilmente para probar. – cletus

Respuesta

5

que debe ser:

class SumSet<E extends Addable<E>> implements Set<E> { 

Su código original especifica que cada elemento de SumSet debe ser una instancia de E, una clase que implementa Addable (lo que equivale a Addable<Object>). Al cambiar Addable a Addable<E>, está especificando que los métodos add, sub y zero de la clase E deben aceptar y devolver instancias de E (en lugar de solo Object).

Tenga en cuenta que la variable de tipo E en SumSet no tiene nada que ver con la variable E anterior. Entonces:

class SumSet<T extends Addable<T>> implements Set<T> { 

    private T element; 

    public SumSet(T element) { 
     this.element = element; 
    } 

    public T getSum() { 
     return element.add(element.zero()); 
    } 
} 

funciona bien también.

+0

Sí, eso sí funciona de la manera esperada. ¡Gracias! –

9

Probar:

class SumSet<E extends Addable<E>> implements Set<E> { 

No sé si esto es exactamente lo que quieres decir, pero, básicamente, el problema es que usted está utilizando Addable en la declaración de SumSet como un tipo de prima. Que se despoja de todos los tipos de parámetros genéricos y hace Addable parecen SumSet como:

interface Addable { 
    Object add(Object x); 
    Object sub(Object y); 
    Object zero(); 
} 

Obviamente Object no es una E, de ahí el error. Consulte What is the raw type? de las preguntas frecuentes de Java Generics.

En una nota lateral public es innecesario en los métodos en las definiciones de interfaz.

+0

¡El tipo de borrado vuelve a golpear! @devoured: Java no tiene idea de qué genéricos están en tiempo de ejecución, por lo que simplemente los ignora. Esto ocasionalmente causa bichos divertidos como este. – ehdv

+0

En una nota lateral, "public" no es necesario en los métodos en las definiciones de interfaz ** public **. – whiskeysierra

3

Debe decir <E extends Addable<E>>, no <E extends Addable>.

Esto se debe a que cuando se utiliza un tipo sin formato, todas las referencias a sus parámetros de tipo (inexistentes) se borran.

0

En lugar de crear una clase SumSet que implementa Set, es posible que desee considerar si puede obtener lo que necesita escribiendo un método que pueda sumar todos los elementos del conjunto.

public static <T extends Addable<T> > T sum(Set<T> set) 
{ 
    T sum = null; 
    for (T t : set) 
    { 
     if (sum == null) 
     { 
      sum = t; 
     } 
     else 
     { 
      sum = sum.add(t); 
     } 
    } 
    return sum; 
} 
Cuestiones relacionadas