A continuación se muestra un ejemplo de lo que estoy tratando de lograr. Estoy tratando de crear LibraryRunner que implementa GenericRunner . Sin embargo, recibo una advertencia del IDE de que LibraryRunner no implementa los métodos en la interfaz de GenericRunner . Lo que tiene sentido, la firma del método no coincide, pero ¿cómo puedo hacer que la firma del método coincida mientras sigo usando LibraryCalculator que extiende GenericCalculator ?
public class LibraryRunner implements GenericRunner { @Override public <T> T run(LibraryCalculator<T> calculator) { return T; } } public interface GenericRunner { <T, A> T run(GenericCalculator<T, A> calculator); } public interface LibraryCalculator<T> extends GenericCalculator<T, LibraryAlgorithm> { T calc(LibraryAlgorithm algorithm) throws LibraryException; } public interface GenericCalculator<T, A> { T calc(A algorithm) throws Exception; } public class LibraryException extends Exception { }Cuando anula un método o lo implementa, siempre debe cumplir la condición del método anulado, por ejemplo, aún debería poder llamar a LibraryRunner.run con un parámetro GenericCalculator. de lo contrario no tendrá sentido escribir:
LibraryRunner libRunner = new LibraryRunner(); GenericRunner genRunner = libRunner; genRunner.run(new GenericCalculator<>()); La anulación de la excepción funciona porque cuando llama a GenericCalculator.calc espera cualquier excepción y llama a LibraryCalculator.calc para reducirla a solo LibraryException .
puede buscar métodos de anulación como promesa de más información.
Por la forma en que se definen las interfaces, no puede anular el método y cambiar su firma, incluso si LibraryCalculator es un subtipo de GenericCalculator . La otra respuesta explica por qué.
Una forma de resolver eso es parametrizar la interfaz GenericRunner con el tipo de calculadora:
public interface GenericRunner<T, A, C extends GenericCalculator<T, A>> { T run(C calculator); } public class LibraryRunner<T> implements GenericRunner<T, LibraryAlgorithm, LibraryCalculator<T>> { @Override public T run(LibraryCalculator<T> calculator) { ... } } Pero tenga en cuenta que no puede devolver un Object en el método LibraryRunner , ya que no coincide con T . Si desea devolver un tipo específico como Object (que anula el propósito del LibraryCalculator genérico), debe especificarlo explícitamente:
public class LibraryRunner implements GenericRunner<Object, LibraryAlgorithm, LibraryCalculator<Object>> { @Override public Object run(LibraryCalculator<Object> calculator) { return new Object(); } } Si eso no es lo que desea, depende del usuario de LibraryRunner decidir a qué tipo T debe vincularse.