usar sirve settitle que para codigo java string reflection string-pool

sirve - settitle java



¿Cómo funciona este fragmento de código Java?(Conjunto de cadenas y reflexión) (7)

¿Qué le pasó a Mario?

Lo cambiaste, básicamente. Sí, con la reflexión puede violar la inmutabilidad de las cadenas ... y debido al internamiento de cadenas, eso significa que cualquier uso de "Mario" (que no sea en una expresión constante de cadena más grande, que se habría resuelto en tiempo de compilación) terminará como "Luigi" en el resto del programa.

Este tipo de cosas es la razón por la cual la reflexión requiere permisos de seguridad ...

Tenga en cuenta que la expresión str + " " + "Mario" no realiza ninguna concatenación en tiempo de compilación, debido a la asociatividad izquierda de + . Es efectivamente (str + " ") + "Mario" , por lo que todavía ves a Luigi Luigi . Si cambia el código a:

System.out.println(str + (" " + "Mario"));

... entonces verás a Luigi Mario ya que el compilador habrá internado a " Mario" en una cadena diferente a "Mario" .

Esta pregunta ya tiene una respuesta aquí:

El conjunto de cadenas de Java junto con la reflexión puede producir un resultado inimaginable en Java:

import java.lang.reflect.Field; class MessingWithString { public static void main (String[] args) { String str = "Mario"; toLuigi(str); System.out.println(str + " " + "Mario"); } public static void toLuigi(String original) { try { Field stringValue = String.class.getDeclaredField("value"); stringValue.setAccessible(true); stringValue.set(original, "Luigi".toCharArray()); } catch (Exception ex) { // Ignore exceptions } } }

El código anterior se imprimirá:

"Luigi Luigi"

¿Qué le pasó a Mario?


Acabas de cambiar el grupo constante de String of String Mario a Luigi que fue referenciado por múltiples String s, por lo que cada referencia literal de Mario ahora es Luigi .

Field stringValue = String.class.getDeclaredField("value");

Ha obtenido el campo de value nombre char[] de la clase String

stringValue.setAccessible(true);

Hazlo accesible.

stringValue.set(original, "Luigi".toCharArray());

String campo original String a Luigi . Pero el original es Mario the String literal y literal pertenece al grupo de String y todos están internados . Lo que significa que todos los literales que tienen el mismo contenido se refieren a la misma dirección de memoria.

String a = "Mario";//Created in String pool String b = "Mario";//Refers to the same Mario of String pool a == b//TRUE //You changed ''a'' to Luigi and ''b'' don''t know that //''a'' has been internally changed and //''b'' still refers to the same address.

Básicamente, ha cambiado el grupo Mario of String que se reflejó en todos los campos de referencia. Si crea un Object String (es decir, una new String("Mario") ) en lugar de literal, no enfrentará este comportamiento porque tendrá dos Mario s diferentes.


Estaba configurado para Luigi. Las cadenas en Java son inmutables; por lo tanto, el compilador puede interpretar todas las menciones de "Mario" como referencias al mismo elemento de agrupación constante de Cadena (aproximadamente, "ubicación de memoria"). Usaste reflejo para cambiar ese elemento; así que todos los "Mario" en su código ahora son como si escribiera "Luigi" .


Las otras respuestas explican adecuadamente lo que está sucediendo. Solo quería agregar el punto de que esto solo funciona si no hay un administrador de seguridad instalado. Cuando se ejecuta código desde la línea de comandos de forma predeterminada, no existe, y puede hacer cosas como esta. Sin embargo, en un entorno donde el código de confianza se mezcla con código no confiable, como un servidor de aplicaciones en un entorno de producción o un sandbox de applet en un navegador, normalmente habrá un administrador de seguridad presente y no se le permitirán este tipo de travesuras, por lo que Esto es menos de un terrible agujero de seguridad como parece.


Los literales de cadena se almacenan en el grupo de cadenas y se utiliza su valor canónico. Ambos literales "Mario" no son solo cadenas con el mismo valor, son el mismo objeto . Manipular uno de ellos (usando la reflexión) modificará "ambos", ya que son solo dos referencias al mismo objeto.


Otro punto relacionado: puede utilizar el grupo constante para mejorar el rendimiento de las comparaciones de cadenas en algunas circunstancias, utilizando el método String.intern() .

Ese método devuelve la instancia de String con el mismo contenido que el String en el que se invoca desde el grupo de constantes de String, y lo agrega si aún no está presente. En otras palabras, después de usar intern() , se garantiza que todas las cadenas con el mismo contenido serán la misma instancia de cadena entre sí y como cualquier constante de cadena con esos contenidos, lo que significa que puede usar el operador igual ( == ) en ellas .

Este es solo un ejemplo que no es muy útil por sí solo, pero ilustra el punto:

class Key { Key(String keyComponent) { this.keyComponent = keyComponent.intern(); } public boolean equals(Object o) { // String comparison using the equals operator allowed due to the // intern() in the constructor, which guarantees that all values // of keyComponent with the same content will refer to the same // instance of String: return (o instanceof Key) && (keyComponent == ((Key) o).keyComponent); } public int hashCode() { return keyComponent.hashCode(); } boolean isSpecialCase() { // String comparison using equals operator valid due to use of // intern() in constructor, which guarantees that any keyComponent // with the same contents as the SPECIAL_CASE constant will // refer to the same instance of String: return keyComponent == SPECIAL_CASE; } private final String keyComponent; private static final String SPECIAL_CASE = "SpecialCase"; }

Este pequeño truco no vale la pena diseñar su código, pero vale la pena tenerlo en cuenta para el día en que note que se puede obtener un poco más de velocidad de un poco de código sensible al rendimiento utilizando el operador == en una cadena con uso juicioso de intern() .


Para explicar un poco más las respuestas existentes, echemos un vistazo a su código de bytes generado (solo el método main() aquí).

Ahora, cualquier cambio en el contenido de esa ubicación afectará tanto a las referencias (como a cualquier otra que proporcione también).