¿Cuáles son buenas razones para prohibir la herencia en Java, por ejemplo, usando clases finales o clases usando un único constructor privado sin parámetros? ¿Cuáles son buenas razones para hacer un método final?
¿Cuáles son buenas razones para prohibir la herencia en Java, por ejemplo, usando clases finales o clases usando un único constructor privado sin parámetros? ¿Cuáles son buenas razones para hacer un método final?
Respuestas:
Su mejor referencia aquí es el Artículo 19 del excelente libro de Joshua Bloch "Java eficaz", llamado "Diseñe y documente la herencia o prohíbala". (Es el ítem 17 en la segunda edición y el ítem 15 en la primera edición). Realmente deberías leerlo, pero lo resumiré.
La interacción de las clases heredadas con sus padres puede ser sorprendente e impredecible si el antepasado no fue diseñado para ser heredado.
Por lo tanto, las clases deben venir en dos tipos:
Clases diseñadas para extenderse y con suficiente documentación para describir cómo debe hacerse
Clases marcadas final
Si está escribiendo código puramente interno, esto puede ser un poco exagerado. Sin embargo, el esfuerzo adicional que implica agregar cinco caracteres a un archivo de clase es muy pequeño. Si está escribiendo solo para consumo interno, entonces un futuro codificador siempre puede eliminar el 'final'; puede pensarlo como una advertencia que dice "esta clase no fue diseñada teniendo en cuenta la herencia".
Es posible que desee hacer que un método sea final para que las clases anuladas no puedan cambiar el comportamiento con el que se cuenta en otros métodos. Los métodos llamados en los constructores a menudo se declaran finales para que no tenga sorpresas desagradables al crear objetos.
final
.
Una razón para hacer una clase final sería si quisieras forzar la composición sobre la herencia. Esto es generalmente deseable para evitar un acoplamiento estrecho entre clases.
Hay 3 casos de uso en los que puede recurrir a los métodos finales.
Propósito para hacer una clase final:
Para que ningún cuerpo pueda extender esas clases y cambiar su comportamiento.
Por ejemplo: clase Wrapper Integer es una clase final. Si esa clase no es final, cualquiera puede extender Integer a su propia clase y cambiar el comportamiento básico de la clase entera. Para evitar esto, Java hizo todas las clases de contenedor como clases finales.
DerivedInteger
, todavía no cambia la clase Integer original, y quien lo use lo DerivedInteger
hace bajo su propio riesgo, por lo que todavía no entiendo por qué es un problema.
es posible que desee crear objetos inmutables ( http://en.wikipedia.org/wiki/Immutable_object ), puede crear un singleton ( http://en.wikipedia.org/wiki/Singleton_pattern ), o puede querer para evitar que alguien anule el método por razones de eficiencia o seguridad.
La herencia es como una motosierra: muy poderosa, pero horrible en las manos equivocadas. O diseñas una clase de la que se hereda (lo que puede limitar la flexibilidad y tomar mucho más tiempo) o deberías prohibirla.
Consulte los artículos 16 y 17 de Java 2nd Edition efectivos, o la publicación de mi blog "Impuesto de sucesiones" .
Hmmm ... puedo pensar en dos cosas:
Es posible que tenga una clase que se ocupe de ciertos problemas de seguridad. Al subclasificarlo y alimentar su sistema con la versión subclasificada, un atacante puede eludir las restricciones de seguridad. Por ejemplo, su aplicación puede admitir complementos y si un complemento puede simplemente subclasificar sus clases relevantes de seguridad, puede usar este truco para de alguna manera pasar de contrabando una versión subclasificada. Sin embargo, esto es algo con lo que Sun tiene que lidiar con respecto a los applets y similares, tal vez no sea un caso tan realista.
Una mucho más realista es evitar que un objeto se vuelva mutable. Por ejemplo, dado que las cadenas son inmutables, su código puede guardar referencias de manera segura
String blah = someOtherString;
en lugar de copiar la cadena primero. Sin embargo, si puede subclasificar String, puede agregarle métodos que permitan modificar el valor de la cadena, ahora ya no puede confiar en que la cadena se mantendrá igual si solo copia la cadena como se indicó anteriormente, en su lugar, debe duplicar cuerda.
Además, si está escribiendo una clase comercial de código cerrado, es posible que no desee que las personas puedan cambiar la funcionalidad en el futuro, especialmente si necesita brindarle soporte y las personas han anulado su método y se quejan de que llamarlo da resultados inesperados
Si marca las clases y los métodos como finales, puede notar una pequeña ganancia de rendimiento, ya que el tiempo de ejecución no tiene que buscar el método de clase correcto para invocar un objeto determinado. Los métodos no finales se marcan como virtuales para que puedan ampliarse adecuadamente si es necesario, los métodos finales se pueden vincular directamente o compilar en línea en la clase.
Para evitar que las personas hagan cosas que puedan confundir a sí mismas y a los demás. Imagine una biblioteca de física donde tiene algunas constantes o cálculos definidos. Sin usar la palabra clave final, alguien podría venir y redefinir cálculos básicos o constantes que NUNCA deberían cambiar.
Desea hacer un método final para que anular clases no cambie su comportamiento. Cuando desee poder cambiar el comportamiento, haga público el método. Cuando anula un método público, se puede cambiar.