2010-03-10 27 views
29

Considere tengo la siguiente interfaz:interfaces Java y tipos devueltos

public interface A { public void b(); } 

Sin embargo quiero cada una de las clases que implementan para tener un tipo de retorno diferente para el método b().

Ejemplos:

public class C { 
    public C b() {} 
} 

public class D { 
    public D b() {} 
} 

¿Cómo defino mi interfaz para que esto fuera posible?

Respuesta

45

Si el tipo de retorno debe ser el tipo de la clase que implementa la interfaz, lo que quiere que se llama un F-bounded type:

public interface A<T extends A<T>>{ public T b(); } 

public class C implements A<C>{ 
    public C b() { ... } 
} 

public class D implements A<D>{ 
    public D b() { ... } 
} 

En palabras, A declara un parámetro de tipo T que asuma el valor de cada tipo de concreto que implementa A. Esto se usa generalmente para declarar cosas como clone() o copy() métodos que están bien tipados. Como otro ejemplo, es usado por java.lang.Enum para declarar que el método compareTo(E) heredado de cada enum aplica solo a otras enumeraciones de ese tipo en particular.

Si utiliza este patrón con la suficiente frecuencia, se encontrará con escenarios en los que necesita this para ser del tipo T. A primera vista podría parecer obvio que es , pero usted necesita realmente para declarar un método abstract T getThis() el que los ejecutores tendrán que implementar trivialmente como return this.

[1] Como comentaron los comentaristas, es posible hacer algo furtivo como X implements A<Y> si X y cooperan adecuadamente. La presencia de un método T getThis() hace aún más claro que X está eludiendo las intenciones del autor de la interfaz A.

+0

+! - Muy agradable. Aprendí algo aquí. Gracias, Matt. – duffymo

+0

fuera de tema: una sintaxis como esta es la razón por la cual hago todo lo posible para evitar crear API genérica tanto como sea posible. – dimitarvp

+1

Buena respuesta (y un gran ejemplo del poder de los genéricos), pero ello no impide al programador de C haciendo implementa un (ver mi segunda respuesta). – Cam

34

genéricos.

public interface A<E>{ 
    public E b(); 
} 

public class C implements A<C>{ 
    public C b(){ 
     return new C(); 
    } 
} 

public class D implements A<D>{ 
    public D b(){ 
     return new D(); 
    } 
} 

buscar hasta genéricos para más detalles, pero (muy), básicamente, lo que sucede es que A deja E 's escriba hasta las clases de aplicación (C y D).

Así que, básicamente, una no sabe (y no tiene que saber) lo que E podría estar en cualquier aplicación dada.

+3

Me gusta más que la marcada como "la" respuesta, porque no tiene que depender del hecho de que los implementadores realmente incluirán su nombre de clase en la declaración genérica. Un pulgar arriba de mí en ese. – dimitarvp

+0

Esto funciona para cualquier tipo de devolución –

2

Desde Java supports covariant return types (desde Java 1.5), que puede hacer:

public interface A { public Object b(); } 
+7

No es genial. Desea que su interfaz deje el menor espacio posible para el uso indebido accidental. Con un método como ese, sería muy fácil para el programador cometer un error al implementar 'A'. – Cam

+0

La pregunta no especificaba explícitamente ninguna restricción en los tipos superiores. Por supuesto, si existen tales restricciones, uno debe hacerlas cumplir con la interfaz donde sea factible. – meriton

Cuestiones relacionadas