2009-10-26 7 views
11

tengo la siguiente situación:genéricos de Java para hacer cumplir el tipo de retorno del método abstracto

abstract class X { abstract X someMethod (...) {...} }. 

Ahora quiero impedir a cualquier implementación de X para tener su método 'algunMetodo' volver ese tipo de realización particular, no sólo X :

class X1 extends X { X1 someMethod (...) {...} }. 
class X1 extends X { X someMethod (...) {...} }. //want this to be flagged as an error 
class X2 extends X { X1 someMethod (...) {...} }. //want this to be flagged as an error too 

¿Es posible lograr esto usando los genéricos de Java?

EDIT

Okay. Solo hice la pregunta sí/no y obtuve un "sí". Mi culpa. Lo que realmente me interesó es "cómo escribo las declaraciones".

Respuesta

17

Esto también funciona;

abstract class X<T> { 
    public abstract T yourMethod(); 
} 
class X1 extends X<X1> { 
    public X1 yourMethod() { 
     return this; 
    } 
} 
class X2 extends X<X2> { 
    public X2 yourMethod() { 
     return this; 
    } 
} 
+5

Considero que este es un código muy feo, pero también es la única solución que conozco, y soy culpable de usarlo yo mismo ... +1 – rmeador

+0

Pensándolo bien ... ¿Alguien sabe con certeza que este es un característica de Jav –

+0

... de los genéricos de Java, y no solo un subproducto peligroso de la forma en que fueron concebidos/implementados? –

0

Esto debería funcionar bien:

class X<T> { 
    abstract T someMethod(...); 
} 

class X1<T1> extends X 
    T1 someMethod(...) { 
    ... 
    } 
} 
4
abstract class X<I extends X<I>> { 
    protected X(Class<I> implClazz) { 
     if (!getClass().equals(implClazz)) { 
      throw new IllegalArgumentException(); 
     } 
    } 

    abstract I someMethod(); 
} 

Justificación: No se puede hacer referencia al tipo dinámico dentro de los límites de tipo, por lo tanto, la comprobación indirecta en el constructor.

+0

Muchas gracias, muy útil. Habría dado la vuelta a esto, pero recibo una respuesta "Inicie sesión o regístrese". –

+0

Es su razón por la cual la solución de Bjorn todavía me permite escribir "la clase X2 extiende X {X1 someMethod() {...}}" –

+0

Exactamente. El único propósito del constructor es protegerse de eso. – meriton

2

Aquí es un método que le permite devolver un tipo de parámetro para this:

AbstractFoo<T extends AbstractFoo<T>> { 
    /** Subclasses must implement to return {@code this}. */ 
    protected abstract T getThis(); 

    /** Does something interesting and returns this Foo */ 
    public T inheritedThing { 
    /* blah di blah */ 
    return getThis(); 
    } 
} 
Cuestiones relacionadas