Desde que supe que la clase java.lang.String
se declara como final en Java, me preguntaba por qué. No encontré ninguna respuesta en ese entonces, pero esta publicación: ¿Cómo crear una réplica de la clase String en Java? Me recordó mi consulta.
Claro, String proporciona toda la funcionalidad que alguna vez necesité, y nunca pensé en ninguna operación que requiriera una extensión de la clase String, ¡pero aún así nunca sabrás lo que alguien podría necesitar!
Entonces, ¿alguien sabe cuál era la intención de los diseñadores cuando decidieron hacerlo definitivo?
Respuestas:
Es muy útil tener cadenas implementadas como objetos inmutables . Debería leer sobre la inmutabilidad para comprender más al respecto.
Una ventaja de los objetos inmutables es que
(desde aquí ).
Si String no fuera definitivo, podría crear una subclase y tener dos cadenas que se parezcan cuando se "vean como Strings", pero que en realidad son diferentes.
fuente
Este es un buen artículo que describe dos razones ya mencionadas en las respuestas anteriores:
Y este es probablemente el comentario más detallado en ese artículo. Tiene que ver con el conjunto de cadenas en Java y los problemas de seguridad. Se trata de cómo decidir qué entra en el conjunto de cadenas. Suponiendo que ambas cadenas son iguales si su secuencia de caracteres es la misma, entonces tenemos una condición de carrera sobre quién llega primero y junto con los problemas de seguridad. De lo contrario, el conjunto de cadenas contendrá cadenas redundantes, perdiendo así la ventaja de tenerlo en primer lugar. Solo léelo por ti mismo, ¿quieres?
La extensión de String causaría estragos en iguales e internos. JavaDoc dice igual a:
Suponiendo que
java.lang.String
no sea final, aSafeString
podría ser igual a aString
, y viceversa; porque representarían la misma secuencia de personajes.¿Qué sucedería si aplicaras
intern
a unSafeString
-SafeString
iría al grupo de cadenas de la JVM? ElClassLoader
y todos los objetos a los que se hacenSafeString
referencias se bloquearían en su lugar durante la vida útil de la JVM. Tendría una condición de carrera sobre quién podría ser el primero en internar en una secuencia de personajes: tal vezSafeString
ganaría, tal vez unString
, o tal vez unSafeString
cargado por un cargador de clases diferente (por lo tanto, una clase diferente).Si ganaras la carrera en el grupo, este sería un verdadero singleton y las personas podrían acceder a todo tu entorno (caja de arena) a través de la reflexión y
secretKey.intern().getClass().getClassLoader()
.O la JVM podría bloquear este agujero asegurándose de que solo se agregaron objetos de String concretos (y no subclases) al grupo.
Si equals se implementó de manera que
SafeString
! =String
EntoncesSafeString.intern
! =String.intern
, YSafeString
tendría que agregarse al grupo. El grupo se convertiría en un grupo de en<Class, String>
lugar de<String>
y todo lo que necesitaría para ingresar al grupo sería un nuevo cargador de clases.fuente
La razón absolutamente más importante por la que String es inmutable o final es que la utiliza el mecanismo de carga de clases y, por lo tanto, tiene aspectos de seguridad profundos y fundamentales.
Si String hubiera sido mutable o no final, una solicitud para cargar "java.io.Writer" podría haberse cambiado para cargar "mil.vogoon.DiskErasingWriter"
referencia: por qué String es inmutable en Java
fuente
String
es una clase muy básica en Java, muchas cosas dependen de que funcione de cierta manera, por ejemplo, que sea inmutable.Hacer la clase
final
evita las subclases que podrían romper estos supuestos.Tenga en cuenta que, incluso ahora, si usa la reflexión, puede romper cadenas (cambiar su valor o código hash). La reflexión se puede detener con un administrador de seguridad. Si
String
no fuera asífinal
, todos podrían hacerlo.Otras clases que no se declaran le
final
permiten definir subclases algo rotas (podría tener unaList
que agregue a la posición incorrecta, por ejemplo), pero al menos la JVM no depende de esas para sus operaciones principales.fuente
final
en una clase no garantiza la inmutabilidad. Simplemente garantiza que los invariantes de una clase (uno de los cuales puede ser inmutabilidad) no pueden ser modificados por una subclase.Como dijo Bruno, se trata de la inmutabilidad. No se trata solo de cadenas, sino también de cualquier envoltorio, por ejemplo, doble, entero, carácter, etc. Hay muchas razones para esto:
Básicamente, para que usted, como programador, pueda estar seguro de que su cadena nunca se cambiará. También, si sabe cómo funciona, puede mejorar la gestión de la memoria. Intente crear dos cadenas idénticas una tras otra, por ejemplo "hola". Notarás, si depuras, que tienen ID idénticos, eso significa que son exactamente LOS MISMOS objetos. Esto se debe al hecho de que Java te permite hacerlo. Esto no sería posible si las cuerdas fueran muttables. Pueden tener lo mismo que yo, etc., porque nunca cambiarán. Entonces, si alguna vez decide crear 1,000,000 de cadenas "hola", lo que realmente haría es crear 1,000,000 de punteros para "hola". Además, la asignación de cualquier función en una cadena, o cualquier envoltorio por esa razón, daría como resultado la creación de otro objeto (nuevamente observe la ID del objeto: cambiará).
Además, final en Java no significa necesariamente que el objeto no pueda cambiar (es diferente a, por ejemplo, C ++). Significa que la dirección a la que apunta no puede cambiar, pero aún puede cambiar sus propiedades y / o atributos. Por lo tanto, comprender la diferencia entre la inmutabilidad y la final en algunos casos podría ser realmente importante.
HTH
Referencias
fuente
Pudo haber sido para simplificar la implementación. Si diseña una clase que será heredada por los usuarios de la clase, entonces tiene un conjunto completamente nuevo de casos de uso para considerar en su diseño. ¿Qué sucede si hacen esto o aquello con el campo X protegido? Al hacerlo definitivo, pueden centrarse en hacer que la interfaz pública funcione correctamente y asegurarse de que sea sólida.
fuente
Con muchos puntos buenos ya mencionados, me gustaría agregar otro, uno de los motivos por los que String es inmutable en Java es permitir que String almacene en caché su código hash , siendo String inmutable en Java almacena en caché su código hash, y no calculo cada vez que llamamos al método hashcode de String , lo que lo hace muy rápido como clave hashmap para usar en hashmap en Java.
En resumen, porque String es inmutable, nadie puede cambiar su contenido una vez creado, lo que garantiza que hashCode of String sea el mismo en la invocación múltiple.
Si ve que la
String
clase tiene se declara comoy la
hashcode()
función es la siguiente:Si ya es computadora, simplemente devuelva el valor.
fuente
Para asegurarnos de que no obtengamos una mejor implementación. Por supuesto, debería haber sido una interfaz.
[editar] Ah, obteniendo más votos despistados. La respuesta es perfectamente seria. Tuve que programar mi camino alrededor de la estúpida implementación de String varias veces, lo que condujo a una severa pérdida de rendimiento y productividad
fuente
Además de las razones obvias sugeridas en otras respuestas, una idea de hacer que la clase String sea final también podría estar relacionada con la sobrecarga del rendimiento de los métodos virtuales. Recuerde que String es una clase pesada, por lo que esta final significa que no hay sub-implementación con seguridad, significa que no hay sobrecarga de llamadas indirectas. Por supuesto, ahora tenemos cosas como invocación virtual y otras, que siempre hacen este tipo de optimización por usted.
fuente
Además de las razones mencionadas en otras respuestas (seguridad, inmutabilidad, rendimiento), debe tenerse en cuenta que
String
tiene un soporte de idioma especial. Puede escribirString
literales y hay soporte para el+
operador. Permitir que los programadores subclasifiquenString
, fomentaría hacks como:fuente
Bueno, tengo un pensamiento diferente, no estoy seguro de si estoy en lo correcto o no, pero en Java String es el único objeto que puede ser tratado como un tipo de datos primitivo, quiero decir que podemos crear un objeto String como String name = "java " . Ahora, como otros tipos de datos primitivos que se copian por valor, no se copian por referencia , se espera que String tenga el mismo comportamiento, por lo que String es final. Eso es lo que pensé. Por favor ignore si es completamente ilógico.
fuente
La finalidad de las cadenas también las defiende como estándar. En C ++ puede crear subclases de cadena, por lo que cada tienda de programación podría tener su propia versión de cadena. Esto llevaría a la falta de un estándar fuerte.
fuente
Digamos que tienes una
Employee
clase que tiene un métodogreet
. Cuandogreet
se llama al método, simplemente se imprimeHello everyone!
. Ese es el comportamiento esperado delgreet
métodoAhora, deje que la
GrumpyEmployee
subclaseEmployee
y anule elgreet
método como se muestra a continuación.Ahora, en el siguiente código, eche un vistazo al
sayHello
método. TomaEmployee
instancia como parámetro y llama al método greet esperando que digaHello everyone!
Pero lo que obtenemos esGet lost!
. Este cambio de comportamiento se debe aEmployee grumpyEmployee = new GrumpyEmployee();
Esta situación se puede evitar si
Employee
se realizó la clasefinal
. Ahora depende de su imaginación la cantidad de caos que un programador descarado podría causar si laString
Clase no se declarara comofinal
.fuente
¿JVM sabe lo que es inmutable? La respuesta es No, el grupo constante contiene todos los campos inmutables, pero todos los campos / objetos inmutables no se almacenan solo en el grupo constante. Solo lo implementamos de manera que logre la inmutabilidad y sus características. CustomString podría implementarse sin que sea final utilizando MarkerInterface, lo que proporcionaría un comportamiento especial de Java para su agrupación, ¡la característica aún está esperando!
fuente
La mayoría de las respuestas están relacionadas con la inmutabilidad: por qué un objeto de tipo String no se puede actualizar en su lugar. Aquí hay mucha buena discusión, y la comunidad Java haría bien en adoptar la inmutabilidad como principal. (No aguanto la respiración)
Sin embargo, la pregunta del OP es por qué es final, por qué no se puede extender. Algunos aquí asumieron esto, pero estaría de acuerdo con el OP que hay una brecha real aquí. Otro lenguaje permite a los desarrolladores crear nuevos tipos nominales para un tipo. Por ejemplo, en Haskell puedo crear los siguientes tipos nuevos que son idénticos en tiempo de ejecución como texto, pero proporcionan seguridad de enlace en tiempo de compilación.
Por lo tanto, propondría la siguiente sugerencia como una mejora del lenguaje Java:
(O tal vez podríamos comenzar a alejarnos de Java)
fuente
Si crea una cadena una vez, lo considerará, es un objeto si desea modificar eso, no es posible, creará un nuevo objeto.
fuente