java string immutability final

java - Clase de cadena final vs métodos finales de clase de cadena no final



string immutability (9)

En palabras sencillas, ¿puedo alcanzar el mismo nivel de inmutabilidad yendo con cualquiera de los dos enfoques? ¿Son ambos buenos para hacer objetos inmutables?

No. Si la clase String no es definitiva, entonces alguien puede extender String y crear una subclase que sea mutable. Todos los desarrolladores de Java perderían la capacidad de asumir que las cadenas son seguras para subprocesos.

Sé que la clase java.lang.String se declara como final por motivos relacionados con la seguridad y el rendimiento.

Lo que no entiendo es la parte de si se podría lograr el mismo propósito utilizando todas las variables finales y los métodos finales en lugar de declarar la clase final.

En resumen, ¿cuál es la diferencia entre los siguientes dos fragmentos de código ... por ejemplo,

public class final String { .. }

v / s

// non final class public class String { // all final variables private final char[] value; // all final methods public final String subString() { .. } public final int length() { return value.length;} // etc }

EDICIONES

En palabras sencillas, ¿puedo alcanzar el mismo nivel de inmutabilidad yendo con cualquiera de los dos enfoques? ¿Son ambos buenos para hacer objetos inmutables?


Lo que no entiendo es la parte de si se podría lograr el mismo propósito utilizando todas las variables finales y los métodos finales en lugar de declarar la clase final.

El propósito de declarar una clase como final no es el mismo que el propósito detrás de declarar todos los métodos en una clase como final.

Clases finales

Cuando declaro una clase A como final, estoy indicando que dicha clase está congelada , no está destinada a la extensión y que no debe utilizarse de ninguna otra forma que no sea la expresada en su estructura y declaraciones. La clase A en virtud de ser definitiva no está abierta al refinamiento.

NOTA 1: Siempre que necesite usar algo que sea de tipo A, hay una, y solo una clase, un tipo, es decir, A que puede usar. La restricción es intencional según el diseño que persiga o según sus requisitos.

La clase java.lang.System es un buen ejemplo. En tiempo de ejecución hay un tipo de sistema. Uno podría tener múltiples instancias de ese sistema (o, como en Java, una especie de envoltorio Singleton para un sistema). Pero el tipo, las capacidades de ese tipo de sistema es uno y solo uno.

Clases con métodos finales

Por otro lado, una clase A con todos los métodos final es simplemente decir lo que te ofrezco , no puedes extender. Sin embargo, puedes agregar más funcionalidad o estado a una extensión mía.

NOTA 2: Siempre que necesite usar una clase A que no sea definitiva, pero que tenga la mayoría de los métodos como final, puede usar una instancia de A o una subclase de la misma. Puede usar una subclase de A en un contexto diferente, pero la funcionalidad principal proporcionada por el tipo A no se modifica.

No puedo imaginar un buen ejemplo donde todos los métodos sean finales. Lo que normalmente veo es una combinación de métodos que son final junto con métodos que son abstract . En tales casos, los métodos finales implementan algoritmos cuyos detalles se extienden a través de métodos abstractos.

Considere el ejemplo poco imaginativo y bastante detallado (a propósito) de una clase de monitor de acceso que congela la lógica de autorización principal (es decir, una excepción para cualquier persona a menos que el usuario esté autorizado). Los detalles adicionales se dejan "en blanco", que se completarán por clase especializaciones.

class AccessMonitor { abstract AuthorizationMechanism getUnderlyingMechanism(); final void checkAccess(User user) { AuthorizationMechanism mechanism = getUnderlyingMechanism() if( mechanism.noAccess(user) ) { throw someSecurityException("blah"); } // otherwise, happy camper } } class LdapBasedMonitor extends AccessMonitor { final AuthorizationMechanism getUnderlyingMechanism() { return someLdapThingieMajingie; } } class DbBasedAuthenticator extends Authenticator { final AuthorizationMechanism getUnderlyingMechanism() { //query some database and make a decision, something something. } }

En la vida real normalmente vemos otras alternativas sobre el refinamiento puro por herencia: la composición y la delegación vienen a la mente. De hecho, en el caso general, uno preferiría la composición / delegación sobre la herencia.

Sin embargo, ese es un tema completamente diferente (uno vale uno o dos libros), y un ejemplo basado en la herencia sirve mejor en este contexto para ilustrar el punto de tener clases no finales con métodos finales.

Este último ejemplo ilustra la idea de tener una clase no final con todos los métodos finales (incluso si el ejemplo deja espacio para métodos abstractos). Cuando se compara con el anterior en esta misma respuesta, espero que pueda ver la diferencia en la intención detrás de los dos.


El modificador final en una clase no significa que las propiedades también sean finales e inmutables. Solo significa que la clase ya no puede ser una clase padre. No es posible extender una clase final.

Ver Uso de la clase final en Java.


Eso depende de cómo definamos lo inmutable. Podríamos llamar inmutable a un objeto si

  1. todos los campos del objeto son finales y los del tipo de referencia que se sabe apuntan a clases inmutables
  2. el estado observable del objeto no debe cambiar, donde el observable se define por
    1. accesible a través de métodos públicos, o
    2. Accesible a través de métodos públicos de alguna clase particular.

Si usamos la definición 1, la clase en sí debe ser final, ya que de lo contrario una subclase podría declarar un nuevo campo no final.

Si usamos la definición 2.1, la clase en sí también debe ser final, ya que de lo contrario podría declarar un campo no final con getter y setter.

Si usamos la definición 2.2, es suficiente si cada campo es final o privado, cada método final o privado, y todos los métodos existentes de la clase conservan la inmutabilidad. (Podríamos relajarlo para incluir campos y métodos protegidos por paquetes, si conocemos el paquete que se va a sellar y verificamos que todos los demás códigos del paquete conservan la inmutabilidad y la encapsulación).

Para la seguridad de la plataforma Java, la definición 2.2 y el enfoque de implementación descrito anteriormente serían suficientes. Sin embargo, sería un poco más complicado comunicar, implementar y verificar que declarar a la clase como definitiva. Dado que una violación de ese invariante comprometería la seguridad de la plataforma, sería sensato adoptar un enfoque más simple y confiable.


Final tiene diferentes efectos dependiendo de donde lo uses.

Si una clase es final, no puede ser subclasificada.

Si un método es definitivo, no puede ser reemplazado por ninguna subclase.

Si una variable es final, solo se puede inicializar una vez, haciéndola constante.


La final es como const en C ++, por lo tanto, no puedes cambiar el estado de la misma. Inmutable es la funcionalidad interna de la clase String. Lo que puedes hacer es usar StringBuilder para lograrlo. Los objetos inmutables crean una nueva instancia en la RAM cada vez que le asigna un nuevo valor. Nunca modifico su estado y, por lo tanto, se crea una nueva instancia a la que se hace referencia como paso por referencia.


Las clases finales no se pueden extender.

Las clases no finales con métodos finales se pueden ampliar (los nuevos métodos se pueden agregar en subclases) pero los métodos finales existentes no se pueden anular.


Te olvidaste de Constructor. El constructor no puede ser definitivo. Para evitar situaciones de Is-A .

Si no está marcando la clase como final, aunque todos sus métodos son definitivos, aún podemos extender la Cadena y podemos hacer trampas en las que se afirma que mi clase también es una clase de Cadena.

Si String por sí solo no es definitivo y los métodos son definitivos, lo siguiente es legal, lo que causa problemas

public class MyUnTrustedClass extends String { void MyUnTrustedClass(String virus){ super(virus); } }


public final String { ... } public ExtendedString extends String { ... } // compiler error

public String { ... } public ExtendedString extends String { ... } // fine

Un poco más de explicación:

Hacer una final de clase también hace implícitamente todos los métodos finales, pero también prohíbe incluso extender la clase. Hacer los métodos definitivos solo permite extender la clase y solo prohíbe anular los métodos finales. En este último caso, aún puede declarar métodos completamente nuevos en la clase extendida.

Una clase de String no final con todos los métodos finales aún sería inmutable (si se aplican todos los demás aspectos de inmutabilidad). Tenga en cuenta que hacer una final de clase es mucho menos esfuerzo para hacerlo inmutable. De hecho, incluso una clase no final puede ser inmutable si se diseña correctamente.