funciones - string[] java
¿Cuál es la diferencia entre "texto" y una nueva cadena("texto")? (9)
JLS
El concepto se llama "internamiento" por el JLS.
Pasaje relevante de JLS 7 3.10.5 :
Además, un literal de cadena siempre se refiere a la misma instancia de clase String. Esto se debe a que los literales de cadena (o, más generalmente, las cadenas que son los valores de las expresiones constantes (§15.28)) son "internados" para compartir instancias únicas, utilizando el método String.intern.
Ejemplo 3.10.5-1. Literales de cuerda
El programa que consiste en la unidad de compilación (§7.3):
package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }
y la unidad de compilación:
package other; public class Other { public static String hello = "Hello"; }
produce la salida:
true true true true false true
JVMS
Un literal de cadena es una referencia a una instancia de clase String, y se deriva de una estructura CONSTANT_String_info (§4.4.3) en la representación binaria de una clase o interfaz. La estructura CONSTANT_String_info proporciona la secuencia de puntos de código Unicode que constituyen la cadena literal.
El lenguaje de programación Java requiere que los literales de cadena idénticos (es decir, los literales que contienen la misma secuencia de puntos de código) se refieran a la misma instancia de la clase String (JLS §3.10.5). Además, si se llama al método String.intern en cualquier cadena, el resultado es una referencia a la misma instancia de clase que se devolvería si esa cadena apareciera como un literal. Por lo tanto, la siguiente expresión debe tener el valor verdadero:
("a" + "b" + "c").intern() == "abc"
Para derivar un literal de cadena, la Máquina Virtual Java examina la secuencia de puntos de código dada por la estructura CONSTANT_String_info.
Si el método String.intern ha sido invocado previamente en una instancia de clase String que contiene una secuencia de puntos de código Unicode idénticos a los de la estructura CONSTANT_String_info, el resultado de la derivación literal de cadena es una referencia a esa misma instancia de clase String.
De lo contrario, se crea una nueva instancia de clase String que contiene la secuencia de puntos de código Unicode dada por la estructura CONSTANT_String_info; una referencia a esa instancia de clase es el resultado de la derivación literal de cadena. Finalmente, se invoca el método interno de la nueva instancia de String.
Bytecode
También es instructivo observar la implementación de bytecode en OpenJDK 7.
Si descompilamos:
public class StringPool {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a);
System.out.println(b);
System.out.println(a == c);
}
}
tenemos en el grupo constante:
#2 = String #32 // abc
[...]
#32 = Utf8 abc
y main
:
0: ldc #2 // String abc
2: astore_1
3: ldc #2 // String abc
5: astore_2
6: new #3 // class java/lang/String
9: dup
10: ldc #2 // String abc
12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
Tenga en cuenta cómo:
-
0
y3
: se carga la misma constanteldc #2
(los literales) -
12
: se crea una nueva instancia de cadena (con#2
como argumento) -
35
:a
yc
se comparan como objetos regulares conif_acmpne
La representación de cadenas constantes es bastante mágica en el bytecode:
- tiene una estructura CONSTANT_String_info dedicada, a diferencia de los objetos normales (por ejemplo,
new String
) - la estructura apunta a una estructura CONSTANT_Utf8_info que contiene los datos. Ese es el único dato necesario para representar la cadena.
y la cita de JVMS anterior parece decir que siempre que el Utf8 señalado es el mismo, entonces instancias idénticas son cargadas por ldc
.
He hecho pruebas similares para los campos, y:
-
static final String s = "abc"
apunta a la tabla de constantes a través del atributo ConstantValue - los campos no finales no tienen ese atributo, pero aún se pueden inicializar con
ldc
Conclusión : existe una compatibilidad directa con bytecode para el grupo de cadenas, y la representación de la memoria es eficiente.
Bonificación: compare eso con el conjunto de enteros , que no tiene soporte directo de bytecode (es decir, ningún análogo CONSTANT_String_info
).
¿Cuál es la diferencia entre estas dos afirmaciones siguientes?
String s = "text";
String s = new String("text");
@ Braj: creo que has mencionado al revés. Por favor, corríjame si estoy equivocado
Creación de objetos línea por línea:
String str1 = new String ("java5")
Pool- "java5" (1 Object)
Heap - str1 => "java5" (1 Object)
Str2 str2 = "java5"
pool- str2 => "java5" (1 Object)
heap - str1 => "java5" (1 Object)
String str3 = new String (str2)
pool- str2 => "java5" (1 Object)
heap- str1 => "java5", str3 => "java5" (2 Objects)
String str4 = "java5"
pool - str2 => str4 => "java5" (1 Object)
heap - str1 => "java5", str3 => "java5" (2 Objects)
Aunque tiene el mismo aspecto desde el punto de vista de los programadores, tiene un gran impacto en el rendimiento. Desearía usar la primera forma casi siempre.
Los literals cadena entrarán en el conjunto constante de cadenas .
La instantánea siguiente puede ayudarlo a comprenderla visualmente para recordarla por más tiempo.
Creación de objetos línea por línea:
String str1 = new String("java5");
Usando el literal de cadena "java5" en el constructor, se almacena un nuevo valor de cadena en el grupo de constante de cadena. Con el nuevo operador, se crea un nuevo objeto de cadena en el montón con "java5" como valor.
String str2 = "java5"
La referencia "str2" apunta al valor ya almacenado en el grupo de constante de cadena
String str3 = new String(str2);
Se crea un nuevo objeto de cadena en el montón con el mismo valor como referencia por "str2"
String str4 = "java5";
La referencia "str4" apunta al valor ya almacenado en el grupo de constante de cadena
Total de objetos: Heap - 2, Pool - 1
Piense en "bla"
como una fábrica de magia como Strings.createString("bla")
(pseudo). La fábrica tiene un conjunto de todas las cadenas aún creadas de esta manera.
Si se invoca, comprueba si ya hay cadena en el grupo con este valor. Si es verdadero, devuelve este objeto de cadena, por lo tanto, las cadenas obtenidas de esta manera son de hecho el mismo objeto.
De lo contrario, crea un nuevo objeto de cadena internamente, lo guarda en el grupo y luego lo devuelve. Por lo tanto, cuando se consulta el mismo valor de cadena la próxima vez, devuelve la misma instancia.
La creación manual de un new String("")
anula este comportamiento omitiendo el grupo de cadenas literales. Por lo tanto, siempre se debe verificar la equals()
usando equals()
que compara la secuencia de caracteres en lugar de la igualdad de referencia del objeto.
Una forma simple de entender la diferencia es a continuación:
String s ="abc";
String s1= "abc";
String s2=new String("abc");
if(s==s1){
System.out.println("s==s1 is true");
}else{
System.out.println("s==s1 is false");
}
if(s==s2){
System.out.println("s==s2 is true");
}else{
System.out.println("s==s2 is false");
}
salida es
s==s1 is true
s==s2 is false
Por lo tanto, el nuevo String () siempre creará una nueva instancia.
Uno crea una cadena en el conjunto constante de cadenas
String s = "text";
el otro crea una cadena en el conjunto constante ( "text"
) y otra cadena en el espacio ( s
) de pila normal. Ambas cadenas tendrán el mismo valor, el de "texto".
String s = new String("text");
s
luego se pierde (elegible para GC) si luego no se usa.
Los literales de cadena, por otro lado, se reutilizan. Si usa "text"
en varios lugares de su clase, de hecho será una y solo una Cadena (es decir, múltiples referencias a la misma cadena en el conjunto).
new String("text");
explícitamente crea una instancia nueva y referencialmente distinta de un objeto String
; String s = "text";
puede reutilizar una instancia del conjunto de constantes de cadena si hay una disponible.
Muy rara vez querrá utilizar el new String(anotherString)
constructor new String(anotherString)
. De la API:
String(String original)
: Inicializa un objetoString
recién creado para que represente la misma secuencia de caracteres que el argumento; en otras palabras, la cadena recién creada es una copia de la cadena del argumento. A menos que se necesite una copia explícita del original, el uso de este constructor es innecesario ya que las cadenas son inmutables.
Preguntas relacionadas
- Java Strings: "String s = new String (" tonto ");"
- Las cadenas son objetos en Java, entonces, ¿por qué no usamos ''nuevo'' para crearlos?
Qué significa la distinción referencial
Examine el siguiente fragmento:
String s1 = "foobar";
String s2 = "foobar";
System.out.println(s1 == s2); // true
s2 = new String("foobar");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
==
en dos tipos de referencia es una comparación de identidad de referencia. Dos objetos que son equals
no son necesariamente ==
. Por lo general, es incorrecto usar ==
en los tipos de referencia; la mayor parte del tiempo equals
a ser usado en su lugar.
No obstante, si por algún motivo necesita crear dos cadenas equals
pero no ==
, puede usar el new String(anotherString)
constructor new String(anotherString)
. Sin embargo, es necesario decir de nuevo que esto es muy peculiar y rara vez es la intención.
Referencias
- JLS 15.21.3 Operadores de igualdad de referencia == y! =
-
class Object
-class Object
boolean Object(equals)
Asuntos relacionados
String str = new String("hello")
Verificará si el conjunto constante de cadenas ya contiene la cadena "hola". Si está presente, entonces no agregará una entrada en el conjunto de constantes de cadena. Si no está presente, agregará una entrada en el grupo de constante de cadena.
Se creará un objeto en un área de memoria de montón y puntos de referencia str
a objeto creado en la ubicación de memoria de montón.
si quiere una referencia str
al objeto de punto que contiene el conjunto de constante de cadena, entonces tiene que llamar explícitamente a str.intern();
String str = "world";
Verificará si el conjunto constante de cadenas ya contiene la cadena "hola". Si está presente, entonces no agregará una entrada en el conjunto de constantes de cadena. Si no está presente, agregará una entrada en el grupo de constante de cadena.
En ambos casos, los puntos de referencia str
a String "world"
presentes en el grupo Constant.