2009-07-07 13 views
5

¿Hay alguna manera de decir "este método devuelve this" usando Generics?¿Hay alguna manera de decir "el método devuelve esto" en Java?

Por supuesto, quiero anular este método en subclases, por lo que la declaración debería funcionar bien con @Override.

Aquí se muestra un ejemplo:

class Base { 
    public Base copyTo (Base dest) { 
     ... copy all fields to dest ... 
     return this; 
    } 
} 
class X extends Base { 
    @Override 
    public X copyTo (X dest) { 
     super.copyTo (dest); 
     ... copy all fields to dest ... 
     return this; 
    } 
} 

public <T extends Base> T copyTo (Base dest) no funciona en absoluto: me sale "No coinciden los tipos: no se puede convertir de base a T". Si lo forzo con un yeso, la anulación falla.

Respuesta

4

No, no hay forma de expresar eso. Simplemente declare el método para devolver el tipo de la clase. Java tiene tipos de retorno covariantes, por lo que puede anular un método para devolver un tipo más específico de todos modos.

Si desea tener algún marcador para esto, siempre puede introducir su propia anotación, pero no espere que otras herramientas la tengan en cuenta.

EDITAR: la respuesta de oxbow_lakes realmente da algo que funcionará en la mayoría de los casos, pero creo que hay formas de engañarlo, de modo que en realidad se trata de un tipo diferente. (De recuerdos de experimentación, de todos modos.) Tenga en cuenta que esto es similar a cómo funcionan las enumeraciones de Java.

+0

Aparte de mi (bueno, de Martin Odersky) forma; detallado arriba –

+0

Sí, aunque hay formas de implementar ese tipo de cosas sin que "Esto" * en realidad * sea Esto. –

5

Puede hacer algo muy inteligente (y similar a lo que han hecho en Scala con el 2.8 collection framework). Declarar algún método de interfaz que debe devolver "en sí" (Nota:This es un parámetro de tipo, no una palabra clave)

public interface Addable<T, This extends Addable<T, This>> { 
    public This add(T t); 
} 

Ahora declaran un nivel de indirección - una clase de "plantilla"

public interface ListTemplate<A, This extends ListTemplate<A, This>> 
    extends Addable<A, This>{ 
} 

public interface List<A> extends ListTemplate<A, List<A>> { 
} 

Entonces una implementación de List tiene que devolver un List del método add (voy a dejar que se llenan los detalles impl)

public class ListImpl<A> implements List<A> { 

    public List<A> add(A a) { 
     return ... 
    } 
} 

mismo modo que podría tener un declard SetTemplate y una Set para extender la interfaz Addable - el método add de lo que habría devuelto un Set. Genial, ¿eh?

0

usando tipos covariantes debe ser simple como:

abstract class Foo<T> { 

    Foo<T> get() { 
     return this.getClass().cast(this); 
    } 
} 

class Bar extends Foo { 

    @Override 
    Bar get() { 
     return (Bar) super.get(); 
    } 
} 
+0

Obtendrás advertencias de tipo no verificadas de javac si hiciste esto –

+0

javac (jdk6) no me da ninguna advertencia. Me falta algo? – dfa

+0

Debe ser: ha ampliado una clase genérica (Foo ) pero no ha proporcionado ningún parámetro de tipo (Bar extends Foo) –

Cuestiones relacionadas