tutorial software pattern patrones patron observer mitocode flyweight diseño curso java design-patterns flyweight-pattern

software - patrones de diseño java tutorial



¿Cómo implementa Java el patrón de peso mosca para una cuerda debajo del capó? (7)

Si tiene dos instancias de una cadena, y son iguales, en Java compartirán la misma memoria

Esto en realidad no es 100% cierto.

Esta publicación de blog es una explicación decente de por qué esto es así, y cuál es el conjunto de cadenas constantes .

Si tiene dos instancias de un String, y son iguales, en Java compartirán la misma memoria. ¿Cómo se implementa esto bajo el capó?

EDITAR: Mi aplicación utiliza una gran cantidad de objetos String, muchos de los cuales son idénticos. ¿Cuál es la mejor manera de hacer uso del conjunto constante de cadenas de Java, para evitar la creación de una implementación de peso mosca personalizada?


Dos cosas a tener en cuenta:

  1. No use el new String("abc") , solo use el literal "abc" .
  2. Aprende a usar el método intern() en la clase String. Especialmente al concatenar cadenas o al convertir char array / byte array / etc en un String.

intern() devuelve siempre las cadenas que están agrupadas.


Eso no es necesario verdad. Ejemplo:

String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2); // true

pero:

String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1 == s2); // false

Ahora se desalienta la segunda forma. Algunos (incluido yo) piensan que String ni siquiera debería tener un constructor público. Una mejor versión de lo anterior sería:

String s1 = new String("hello").intern(); String s2 = new String("hello").intern(); System.out.println(s1 == s2); // true

Obviamente, no es necesario hacer esto para una String constante. Es ilustrativo

El punto importante de esto es que si se pasa una String o se obtiene una de una función, no se puede confiar en que la String sea canónica . Un Object canónico satisface esta igualdad:

a.equals(b) == b.equals(a) == (a == b)

para instancias no null a , b, de una Class dada.


Los literales de cadena están internados en Java, por lo que en realidad solo hay un objeto String con varias referencias (cuando son iguales, lo que no siempre es así). Vea el artículo de java.net Todo sobre intern () para más detalles.

También hay un buen ejemplo / explicación en la sección 3.10.5 Literales de cadenas del JLS que se refiere a cuándo se internan las cadenas y cuándo serán distintas.


Para responder a su pregunta editada, las JVM de Sun tienen una -XX:+StringCache , que en mi observación puede reducir significativamente la huella de memoria de una aplicación String heavy.

De lo contrario, tiene la opción de internar sus cadenas, pero yo tendría cuidado al respecto. Las cadenas que son muy grandes y ya no están referenciadas seguirán usando la memoria durante la vida útil de la JVM.

Editar (en respuesta al comentario): primero me enteré de la opción StringCache desde here :

-XX: + StringCache Habilita el almacenamiento en caché de cadenas asignadas comúnmente.

Tom Hawtin describe algún tipo de almacenamiento en caché para mejorar algunos puntos de referencia. Mi observación cuando lo puse en IDEA fue que la huella de la memoria (después de una recolección de basura completa) se redujo por no tenerla. No es un parámetro documentado y, de hecho, puede que solo se trate de optimizar algunos puntos de referencia. Mi observación es que ayudó, pero no construiría un sistema importante basado en él.


Si sus Cadenas idénticas provienen de un conjunto fijo de valores posibles, entonces aquí lo que desea es una enumeración de tipo seguro. No solo reducirá su conteo de cadenas, sino que lo hará para una aplicación más sólida. Toda su aplicación sabrá que esta Cadena tiene semántica adjunta, tal vez incluso algunos métodos de conveniencia.

Mis optimizaciones favoritas son siempre las que se pueden defender como mejorar el código, no solo más rápido. Y 9 veces de cada 10, reemplazar una cadena con un tipo concreto lleva a un código más correcto y auto-documentado.


Mire el código fuente de java.lang.String (la fuente para toda la api de java es parte del JDK).

Para resumir: una cadena envuelve una subsecuencia de un char[] . Ese respaldo char[] nunca se modifica. Esto se logra al no filtrar ni capturar este char[] fuera de la clase String . Sin embargo, varias Strings pueden compartir el mismo char[] (ver Implementación de String.substring ).

También existe el mecanismo de internado, como se explica en las otras respuestas.