2010-03-30 18 views
8

He visto diferentes preguntas al respecto, pero todavía encuentro este tema muy confuso.Choque de nombres genéricos de Java, método no correctamente anulado

Todo lo que quiero hacer es tener una clase abstracta que implemente una interfaz y tener una clase que extienda esta clase abstracta para que la clase difícil necesite implementar getKommune() y setKommune(Kommune kommune), pero no el otro método, porque eso está la clase abstracta

Tengo la siguiente interfaz.

public interface KommuneFilter { 

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

    Kommune getKommune(); 

    void setKommune(Kommune kommune); 
} 

Y esta clase abstracta

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

Y quiero utilizar de esta manera

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

Sin embargo, consigo

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

Por qué no está anulado correctamente?

ACTUALIZACIÓN

Gracias a @Bozho, la solución es la siguiente:

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> 

Respuesta

4

yo sugeriría hacer la interfaz genérica, y no sólo su método:

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

Y luego

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

Gracias, esto pareció funcionar. Sin embargo, tal vez podrías por favor hacerme entender por qué esta solución funcionó y no la mía. –

+0

@Shervin: porque en su diseño original, el método especificado por la interfaz es un método genérico, y el intento de su clase abstracta de '@ Override' no es uno. – polygenelubricants

2

La razón por la cual es un choque de nombre y no una anulación es porque no lo es. El método especificado por la interfaz es un método genérico; el intento de tu clase abstracta de anularlo no lo es.

Un código más conciso que reproduce el problema es el siguiente:

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

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

El problema aquí es que interface I especifica que los ejecutores deben proporcionar un método genérico <E>foo (que puede ser una <Integer>foo, <Boolean>foo, etc), pero Por ejemplo, un C<String> realmente solo tiene foo(String).

Una forma de solucionar este problema es hacer C.foo un método genérico, que adecuadamente @Override el método genérico de 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); 
    } 
} 

se puede ver lo que esto hace en el código anterior: usted tiene un tipo genérico C<E> con un método genérico <T>foo (puede usar E en lugar de T, pero eso no cambiaría nada, sigue siendo un método genérico con su propio parámetro de tipo).

Ahora un C<String> también tiene <Integer>foo, etc., como se especifica en interface I.

Si esto no es algo que se necesita, entonces es probable que desee hacer interface I<E> genérico en lugar:

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

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

Ahora el tipo y el método comparte el parámetro mismo tipo (por ejemplo, un I<Boolean> sólo tiene un foo(Boolean) , un C<String> solo tiene un foo(String)) que es probablemente lo que pretendías originalmente.

+0

el problema no es la anotación '@ Override'. Lo que le está diciendo que haga es ocultar el parámetro genérico de la clase introduciendo otro con el mismo nombre en el método. (Eclipse da "El parámetro de tipo E oculta el tipo E") – Bozho

+0

Históricamente, siempre escribo '@ Override' en lugar de" override "para recordarme a mí mismo (y a otros) que siempre use la anotación. Me doy cuenta de que causa confusión aquí. Debería ser más claro ahora. Tienes razón sobre la parte oculta No creo que sea un gran problema personalmente. – polygenelubricants

+1

usando 'T' en lugar de' E' para el método sería mejor, pero el "diseño" completo todavía se siente mal. – Bozho