Digamos que tengo una interfaz Interface que tiene un método aMethod() que debería devolverse a sí mismo, pero también tiene una implementación predeterminada. Luego también tengo una clase Foo que implementa Interface y agrega el método adicional aFooMethod() .
interface Interface { public default Interface aMethod() { // Some code return this; } } class Foo implements Interface { public void aFooMethod() { // Some code } } Ahora no puedo llamar a new Foo().aMethod().aFooMethod(); porque aMethod() devuelve una Interface .
Ahora, obviamente, podría seguir adelante y anular el método en Foo :
class Foo implements Interface { @Override public Foo aMethod() { Interface.super.aMethod(); return this; } public void aFooMethod() { // Some code } }La pregunta que tengo es si hay una buena manera de forzar esto, que una subclase tenga que devolverse a sí misma sin tener que anular ese método.
Mi mejor enfoque es decir algo como esto:
interface Interface<I extends Interface<I>> { @SupressWarnings("unchecked") public default I aMethod() { // Some code return (I)this; } } Pero esto no es lo que consideraría bueno , ya que tiene que usar SupressWarnings("unchecked") . ¿Hay alguna forma mejor?
Recientemente hice una pregunta sobre esto mismo, pero en C#. Sin embargo, tanto el problema como la respuesta siguen siendo los mismos: algo como esto no es posible.
El patrón que mencionas
interface Interface<I extends Interface<I>> {} parece un buen enfoque al principio, pero se desmorona tan pronto como hay más de una clase que implementa Interface . Y el problema no es la necesidad de suprimir una advertencia, en realidad es algo mucho más grande. Si creo dos clases como esta:
class A implements Interface<A> {} class B implements Interface<A> {} seguirá funcionando. La restricción I extends Interface<I> solo obliga al parámetro de tipo I a ser una Interface<I> , y A implementa Interface<A> , por lo que satisface la restricción incluso cuando Interface<A> es implementada por B .
He estado tratando de encontrar formas de evitar esto, pero lamentablemente, ni Java ni C # permiten nada en este sentido.