2010-03-30 13 views
8

Ho visto diverse domande a riguardo, ma trovo ancora questo argomento molto confuso.Nome conflitto Java generico, metodo non sovrascritto correttamente

Tutto quello che voglio fare, è di avere una classe astratta che implementa un'interfaccia, e hanno una classe che estende la classe astratta in modo che la classe difficile deve attuare getKommune() e setKommune(Kommune kommune), ma non l'altro metodo, perché è in la classe astratta.

Ho la seguente interfaccia.

public interface KommuneFilter { 

    <E extends AbstractKommune<?>> void addKommuneFromCurrentUser(E e); 

    Kommune getKommune(); 

    void setKommune(Kommune kommune); 
} 

E questa classe astratta

public abstract class AbstractKommune<E extends AbstractKommune<?>> implements KommuneFilter { 
    @PrePersist 
    void addKommuneFromCurrentUser(E e) { 
      Kommune k = e.getKommune(); 
    } 
} 

E voglio usare in questo modo

public class Person extends AbstractKommune<Person> { 
     private Kommune kommune;    
     public void setKommune(Kommune kommune) {this.kommune=kommune;} 
     public Kommune getKommune() {return kommune;} 
    } 

Tuttavia, ottengo

Name clash: The method of has the same erasure of type but does not override it

perché non è sovrascritto correttamente?

UPDATE

Grazie alla @Bozho, la soluzione è questa:

public interface KommuneFilter<E extends AbstractKommune<?>> { 
    public void addKommuneFromCurrentUser(E e); 
} 

public abstract class AbstractKommune<E extends AbstractKommune<?>> implements KommuneFilter<E> 

public class Person extends AbstractKommune<Person> 

risposta

4

Io suggerirei di rendere l'interfaccia generica, e non solo il suo metodo:

interface KommuneFilter<E extends AbstractKommune<?>> { .. } 

E quindi

public abstract class AbstractKommune<E extends AbstractKommune<?>> 
    implements KommuneFilter<E> 
+0

Grazie, sembra funzionare. Tuttavia, forse potresti farmi capire perché questa soluzione ha funzionato e non il mio. –

+0

@Shervin: poiché nella progettazione originale, il metodo specificato dall'interfaccia è un metodo generico e il tentativo della classe astratta di "@ Sostituire" non è uno. – polygenelubricants

2

Il motivo per cui si tratta di un conflitto di nomi e non di un override è perché non lo è. Il metodo specificato dall'interfaccia è un metodo generico; il tentativo della tua classe astratta di ignorarlo non lo è.

Un codice più conciso che riproduce il problema è questo:

interface I { 
    <E> void foo(E e); 
} 

class C<E> implements I { 
    public void foo(E e) { // name clash at compile time! 
    } 
} 

Il problema qui è che interface I precisa che implementors devono fornire un metodo generico <E>foo (può essere un <Integer>foo, <Boolean>foo, ecc), ma Ad esempio, un C<String> ha solo foo(String).

Un modo per risolvere questo problema è quello di rendere C.foo un metodo generico, correttamente @Override il metodo generico di interface I:

interface I { 
    <E> void foo(E e); 
} 

class C<E> implements I { 
    @Override public <T> void foo(T t) { 
    } 

    public static void main(String args[]) { 
     C<String> o = new C<String>(); 
     o.<Integer>foo(0); 
     o.<Boolean>foo(false); 
    } 
} 

si può vedere ciò che fa nel codice sopra: si dispone di un tipo generico C<E> con un metodo generico <T>foo (è possibile utilizzare E anziché T, ma questo non cambierebbe nulla: è ancora un metodo generico con un proprio parametro di tipo).

Ora un C<String> ha anche <Integer>foo, ecc. Come specificato da interface I.

Se questo non è qualcosa che avete bisogno, allora probabilmente si vuole fare interface I<E> generico invece:

interface I<E> { 
    void foo(E e); 
} 

class C<E> implements I<E> { 
    @Override public void foo(E e) { 
    } 
} 

Ora il tipo e le quote metodo del parametro stesso tipo (ad esempio, un I<Boolean> ha solo una foo(Boolean) , un C<String> ha solo un foo(String)) che è probabilmente quello che avevi inizialmente previsto.

+0

il problema non è l'annotazione '@ Override'. Quello che gli stai dicendo di fare è nascondere il parametro generico dalla classe introducendo un altro con lo stesso nome sul metodo. (Eclipse restituisce "Il parametro di tipo E nasconde il tipo E") – Bozho

+0

Storicamente, scrivo sempre '@ Override' invece di" override "per ricordare a me stesso (e agli altri) di usare sempre l'annotazione. Mi rendo conto che provoca confusione qui. Dovrebbe essere più chiaro ora. Hai ragione riguardo alla parte nascosta; Non penso che sia un grosso problema personalmente. – polygenelubricants

+1

usando 'T' invece di' E' perché il metodo sarebbe migliore, ma l'intero "design" si sente ancora sbagliato. – Bozho

Problemi correlati