son que porque por objetos objeto modificar los inmutables inmutable estructuras clases java oop final

java - que - clase inmutable debe ser final?



porque los string son inmutables (5)

Dice en este artículo que:

Hacer una clase final porque es inmutable es una buena razón para hacerlo.

Estoy un poco desconcertado por esto ... Entiendo que la inmutabilidad es algo bueno del punto de vista de seguridad y simplicidad de las secuencias, pero parece que estas preocupaciones son algo ortogonales a la extensibilidad. Entonces, ¿por qué la inmutabilidad es una buena razón para hacer una clase final?


Porque si la clase es final no puedes extenderla y hacerla mutable.

Incluso si hace que los campos sean finales, eso solo significa que no puede reasignar la referencia, no significa que no puede cambiar el objeto al que se hace referencia.

No veo mucho uso en un diseño para una clase inmutable que también debería extenderse, por lo que final ayuda a mantener la inmutabilidad intacta.


Principalmente la seguridad que pensaría. Por la misma razón, String es definitivo, cualquier cosa que un código relacionado con la seguridad quiera tratar como inmutable debe ser definitiva.

Supongamos que tiene una clase definida como inmutable, llámela MyUrlClass, pero no la marca como definitiva.

Ahora, alguien podría estar tentado a escribir código de administrador de seguridad como este;

void checkUrl(MyUrlClass testurl) throws SecurityException { if (illegalDomains.contains(testurl.getDomain())) throw new SecurityException(); }

Y esto es lo que pondrían en su método DoRequest (MyUrlClass url):

securitymanager.checkUrl(urltoconnect); Socket sckt = opensocket(urltoconnect); sendrequest(sckt); getresponse(sckt);

Pero no pueden hacer esto, porque no hizo que MyUrlClass sea definitiva. La razón por la que no pueden hacerlo es que, si lo hicieran, el código podría evitar las restricciones del administrador de seguridad al anular getDomain () para que devuelva "www.google.com" la primera vez que se llame y "www.evilhackers.org". el segundo, y pasar un objeto de su clase a DoRequest ().

No tengo nada en contra de evilhackers.org, por cierto, si es que existe ...

En ausencia de problemas de seguridad, todo se trata de evitar errores de programación, y depende de usted cómo lo haga. Las subclases deben mantener el contrato de sus padres, y la inmutabilidad es solo una parte del contrato. Pero si se supone que las instancias de una clase son inmutables, entonces hacer que sea definitiva es una buena forma de asegurarse de que realmente sean inmutables (es decir, que no haya instancias mudables de subclases dando vueltas, que pueden usarse en cualquier lugar donde el padre clase es requerida).

No creo que el artículo que mencionó deba tomarse como una instrucción de que "todas las clases inmutables deben ser definitivas", especialmente si tiene una razón positiva para diseñar su clase inmutable de herencia. Lo que estaba diciendo es que proteger la inmutabilidad es una razón válida para el final, donde las preocupaciones de rendimiento imaginario (que es de lo que realmente se habla en ese momento) no son válidas. Tenga en cuenta que dio "una clase compleja no diseñada para la herencia" como una razón igualmente válida. Se puede argumentar de manera justa que no tener en cuenta la herencia en las clases complejas es algo que se debe evitar, así como no tener en cuenta la herencia en las clases inmutables. Pero si no puede explicarlo, al menos puede señalar este hecho previniéndolo.


Siguiendo el Principio de Sustitución de Liskov, una subclase puede extenderse pero nunca redefinir el contrato de su matriz. Si la clase base es inmutable, entonces es difícil encontrar ejemplos de dónde podría extenderse útilmente su funcionalidad sin romper el contrato.

Tenga en cuenta que, en principio, es posible extender una clase inmutable y cambiar los campos base, por ejemplo, si la clase base contiene una referencia a una matriz, los elementos dentro de la matriz no pueden declararse finales. Obviamente, la semántica de los métodos también se puede cambiar mediante la anulación.

Supongo que podría declarar todos los campos como privados y todos los métodos como definitivos, pero ¿cuál sería el uso de heredar?


Es una buena idea hacer una clase inmutable también por motivos de rendimiento. Tome Integer.valueOf por ejemplo. Cuando llamas a este método estático, no tiene que devolver una nueva instancia de Integer. Puede devolver una instancia previamente creada de forma segura sabiendo que cuando le pasó una referencia a esa instancia la última vez no la modificó (supongo que esto también es un buen razonamiento desde el punto de vista de la razón de seguridad).

Estoy de acuerdo con el punto de vista adoptado en Java efectivo sobre estos asuntos: que debe diseñar sus clases para la extensibilidad o hacerlas no extensibles. Si es su intención hacer algo extensible, quizás considere una interfaz o clase abstracta.

Además, no es necesario que la clase sea definitiva. Puedes hacer que los constructores sean privados.


La explicación de esto se da en el libro ''Effective Java''

Considere las clases BigDecimal y BigInteger en Java.

No se entendía ampliamente que las clases inmutables debían ser efectivamente definitivas cuando se escribieron BigInteger y BigDecimal , por lo que todos sus métodos pueden anularse. Desafortunadamente, esto no pudo ser corregido después del hecho mientras se preservaba la compatibilidad con versiones anteriores.

Si escribe una clase cuya seguridad depende de la inmutabilidad de un argumento BigInteger o BigDecimal de un cliente no confiable, debe verificar que el argumento sea un BigInteger o BigDecimal "real", en lugar de una instancia de una subclase no confiable . Si es el último, debes copiarlo defensivamente bajo la suposición de que podría ser mutable.

public static BigInteger safeInstance(BigInteger val) { if (val.getClass() != BigInteger.class) return new BigInteger(val.toByteArray()); return val; }

Si permite la subclasificación, podría romper la "pureza" del objeto inmutable.