2010-04-17 5 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()); 
    } 
} 

Sembra che element.add() non restituisca un E extends Addable ma piuttosto un Object. Perché? Ha qualcosa a che fare con Java che non sa in tempo reale quali sono i tipi di oggetto, quindi si presuppone che siano oggetti (quindi richiedono un cast)?Qual è il problema con questo codice Java relativo a Generics?

Grazie

+2

+1 per la pubblicazione di uno snippet di codice che può essere facilmente tagliato e incollato per testare. – cletus

risposta

5

dovrebbe essere:

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

tuo codice originale specifica che ogni elemento di SumSet deve essere un'istanza di E, una classe che implementa Addable (che equivale a Addable<Object>). Modificando Addable in Addable<E>, si specifica che i metodi add, sub e zero della classe E devono accettare e restituire istanze di E (anziché solo oggetto).

Si noti che la variabile di tipo E in SumSet non ha nulla a che fare con la variabile E sopra. Quindi:

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

funziona bene.

+0

Sì, funziona davvero come previsto. Grazie! –

9

Prova:

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

Non so se questo è esattamente quello che vuoi dire, ma fondamentalmente il problema è che si sta utilizzando Addable nella dichiarazione di SumSet come un tipo grezzo. Che mette nudo tutti i tipi di parametri generici e rende Addable sembrano SumSet come:

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

Ovviamente Object non è un E, quindi l'errore. Vedere What is the raw type? dalle domande frequenti di Java Generics.

Su una nota laterale public non è necessario sui metodi nelle definizioni di interfaccia.

+0

La cancellazione di tipo colpisce ancora! @devoured: Java non ha idea di cosa siano i generici in fase di runtime, quindi li ignora semplicemente. Questo occasionalmente si traduce in bug divertenti come questo. – ehdv

+0

Nota a margine 'public' non è necessaria sui metodi nelle definizioni dell'interfaccia ** pubblica **. – whiskeysierra

3

È necessario dire <E extends Addable<E>>, non <E extends Addable>.

Questo perché quando si utilizza un tipo non elaborato, vengono cancellati tutti i riferimenti ai suoi parametri di tipo (inesistenti).

0

Invece di creare una classe SumSet che implementa Set, è possibile valutare se è possibile ottenere ciò che è necessario scrivendo un metodo che sommi tutti gli elementi nel set.

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