polimorfismo hijo herencia ejemplos derivada clases clase abstracta java interface contract

hijo - herencia java



¿Debería implementarse explícitamente una interfaz heredada de la clase base en la subclase? (11)

Mi pregunta es si la clase debe implementar explícitamente una interfaz que se implementa implícitamente ampliando una clase que ya la implemente, si la clase desea anunciar el hecho de que cumple con el contrato de esa interfaz.

Por ejemplo, si desea escribir una clase, eso cumple el contrato de la interfaz java.util.List . Implementa esto, extendiendo la clase java.util.AbstractList , que ya implementa la List interfaz. ¿Declaras explícitamente que implementas List?

public class MyList extends AbstractList implements List

¿O ahorras escribir usando la forma implícita?

public class MyList extends AbstractList

¿Qué camino se considera mejor estilo? ¿Qué razones tiene que preferir de una forma u otra? ¿En qué situaciones preferirías el modo 1 o el modo 2?


No es una pregunta de "estilo". Si está extendiendo AbstractList que ya implementa List, no necesita implementar explícitamente List.

No es solo una cuestión de ahorrar tipeo. Como la "Lista de implementos" adicional es redundante, alguien podría pasar algún tiempo tratando de descubrir por qué está allí. Básicamente estás escribiendo en una garantía que ya es parte del lenguaje.


Otros comentaristas dicen que debe evitar la redundancia, y yo estoy de acuerdo con ellos.

Para responder a la pregunta general, el único caso en el que puedo pensar para establecer ambos sería si extendieras (digamos) AbstractFrotzer e implementaras Frobner, AbstractFrotzer implementara Frobner, pero tienes razones para creer que podría no suceder en el futuro. Si AbstractFrotzer es realmente abstracto, es posible que ni siquiera implemente todos los métodos de Frobner. Esto significa que es posible que alguien cambie el contrato de AbstractFrotzer sin que tenga que cambiar su clase, o cualquier otro código que se basó en su clase para ser un Frobner. Sin embargo, consideraría que esta es una circunstancia muy rara, e incluso si ocurriera y tu clase solo extendiera AbstractFrotzer, sería bastante fácil darle un chequeo semántico rápido y, si es necesario, agregarle la cláusula de implementaciones en ese punto.


Cuando extiende AbstractList, MyList ya está en ''type'' List, por lo que no es necesario que explícitamente (o implemente) la interfaz.


Evite la redundancia. Usa el método 2.

Use @Override para anulaciones.


Yo diría la manera más literal. ¿Por qué hacer que otros que leen tu código tengan que buscar lo que implementa una clase? Deja en claro la funcionalidad heredada de tu clase. Pero trataría de mantener la coherencia en todo el código del proyecto. Sería confuso si solo lo haces en un lugar, pero si lo haces consistentemente, se dará cuenta de la redundancia.

Una nota al margen: hay tantas clases en Java y ¿quién las conoce todas? Aún más, ¿quién sabe de qué clases implementa cada clase? Escribir durante un par de segundos adicionales le ahorra a un desarrollador compañero un minuto o dos clases que buscan.


Aunque generalmente me quedo con la opción 2, me arriesgaré y argumentaré que la opción 1 es realmente apropiada en más casos cuando se aplica.

La usabilidad y comprensibilidad del código es importante. La pregunta que debemos plantearnos es si un desarrollador que utiliza o ve una referencia a esta clase comprenderá intuitivamente que la clase implementa esa interfaz (y, por lo tanto, es esencialmente un subtipo).

En una clase bien escrita en el caso típico, el nombre de la clase debería hacer obvio que implementa la interfaz. Agregar la interfaz sería solo una redundnacy.

Sin embargo , en los casos en que el nombre de la clase no hace obvio qué interfaces implementa, ya pesar del olor así son las cosas y este es el nombre que se va a atascar, entonces tiene sentido agregar los implementos para indicar explícitamente la interfaz. . Esto también es bueno en caso de que alguien en el futuro cambie la jerarquía, lo que es posible en herencias poco intuitivas como esta.


Como regla general, use la opción 2, no la opción 1.

La opción 1 no proporciona ninguna adición de valor al desarrollador o a alguien que va a mantener el código, en la gran mayoría de los casos.

Si alguien realmente quiere saber todas las raíces de una clase en particular, cualquier IDE debería ser capaz de hacerlo por usted, de manera directa. (Eclipse: ctrl + shift + G)

¿Qué pasa si AbstractList decide no implementar la Lista por más tiempo? Esto no va a suceder para la gran mayoría de las clases generales . ¿Y los otros menos obvios (menos confiables )? Por supuesto, puede haber excepciones, pero muy pocas (<1%?)


He visto esto antes y no me parece técnicamente correcto, como muchos de ustedes ya han señalado. Creo que debería ser obvio, sin embargo, si por alguna razón no lo fuera, creo que tendría más sentido indicar la herencia a través de un comentario de clase, en lugar de implementar explícitamente la interfaz nuevamente.

¿Qué pasa si la clase base implementa múltiples interfaces? ¿Luego implementa explícitamente todas esas interfaces, y todo el camino de regreso a la cadena de herencia? Obviamente no, así que creo que la inconsistencia de este enfoque demuestra ser incorrecta. El intento se puede comunicar de muchas maneras, y este no es el mejor enfoque en mi humilde opinión.


Si te preocupa que un usuario de tu clase pueda obtener una lista de interfaces implementadas a través de Class.getInterfaces (), entonces tu clase debería mencionar todas las interfaces en su lista de implementaciones. Class.getInterfaces () no devolverá las interfaces implementadas por las súper clases. El siguiente programa imprimirá 1 y luego 0.

import java.io.Serializable; class Test implements Serializable { class Inner extends Test { } public static void main(String[] argv) throws Exception { System.out.println(Test.class.getInterfaces().length); System.out.println(Inner.class.getInterfaces().length); } }


Hace mucho tiempo hice esta misma pregunta en mi blog . También hay una larga discusión allí si estás interesado en ver los pensamientos de otras personas. Es interesante observar que ambas estrategias se toman dentro del JDK.

Finalmente decidí que una regla rígida sobre esto no tenía sentido; es mejor usar el mejor juicio sobre lo que quería comunicar.


Aunque es redundante implementar la interfaz en la subclase, es una buena práctica implementarla. Porque alguien podría eliminar la interfaz implementada de la superclase.