Las cadenas son objetos en Java, entonces, ¿por qué no usamos 'nuevo' para crearlos?

104

Normalmente creamos objetos usando la newpalabra clave, como:

Object obj = new Object();

Las cadenas son objetos, pero no las usamos newpara crearlas:

String str = "Hello World";

¿Por qué es esto? ¿Puedo hacer una cadena con new?

giri
fuente
También debería echar un vistazo a esta pregunta stackoverflow.com/questions/456575/java-wrapper-equality-test
cambiado el
1
Porque los literales de cadena ya son objetos.
Marqués de Lorne
1
Tenga en cuenta que new String(...)se ha utilizado para eludir un detalle de implementación al crear subcadenas de cadenas grandes. Esto se solucionó en Java 7 y ya no es necesario.
Thorbjørn Ravn Andersen
Soy el 100º me gusta de esta publicación. :)
Mukit09

Respuestas:

130

Además de lo que ya se dijo, los literales de cadena [es decir, cadenas como "abcd"pero no como new String("abcd")] en Java están internados; esto significa que cada vez que te refieres a "abcd", obtienes una referencia a un soloString instancia, en lugar de una nueva. cada vez. Entonces tendrás:

String a = "abcd";
String b = "abcd";

a == b; //True

pero si tuvieras

String a = new String("abcd");
String b = new String("abcd");

entonces es posible tener

a == b; // False

(y en caso de que alguien necesite recordárselo, utilice siempre .equals() para comparar cadenas; ==pruebas de igualdad física).

Interning String literales es bueno porque a menudo se usan más de una vez. Por ejemplo, considere el código (artificial):

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

Si no tuviéramos internados de Strings, "Next iteration" necesitaría ser instanciado 10 veces, mientras que ahora solo será instanciado una vez.

danben
fuente
1
Al usar String a = new String ("abcd"), ¿significa que dos cadenas con contenido similar están presentes en la memoria?
cambiado el
1
Correcto: el compilador no necesariamente verificará si dicha cadena ya ha sido internada (aunque ciertamente podría escribir una que sí).
danben
eso sí, esta optimización es posible porque las cadenas son inmutables y por tanto se pueden compartir sin problemas. el manejo "asdf" compartido es una implementación del patrón de diseño "Flyweight".
manuel aldana
Nadie dijo que no es posible, solo que no está garantizado. ¿Ese fue tu voto negativo?
danben
¿Qué quieres decir con "== pruebas de igualdad de objetos"? Esto no me parece cierto, pero quizás quisiste decir algo diferente de lo que parece significar.
Dawood ibn Kareem
32

Las cadenas son objetos "especiales" en Java. Los diseñadores de Java decidieron sabiamente que las cadenas se utilizan con tanta frecuencia que necesitaban su propia sintaxis, así como una estrategia de almacenamiento en caché. Cuando declaras una cadena diciendo:

String myString = "something";

myString es una referencia al objeto String con un valor de "algo". Si luego declara:

String myOtherString = "something";

Java es lo suficientemente inteligente como para determinar que myString y myOtherString son iguales y los almacenará en una tabla String global como el mismo objeto. Se basa en el hecho de que no puede modificar Strings para hacer esto. Esto reduce la cantidad de memoria necesaria y puede acelerar las comparaciones.

Si, en cambio, escribes

String myOtherString = new String("something");

Java creará un objeto nuevo para usted, distinto del objeto myString.

Jamie McCrindle
fuente
Oye ... no se requiere "sabiduría infinita" para reconocer la necesidad de algún tipo de soporte sintáctico para cadenas literales. Casi todos los demás diseños de lenguajes de programación serios admiten algún tipo de cadena literal.
Stephen C
12
La hipérbole se ha reducido a aturdir, Capitán :)
Jamie McCrindle
16
String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

Espero que esto aclare algunas dudas. :)

Crocode
fuente
Cadena d = nueva Cadena ("def"); // 1 objeto + "def" se agrega al grupo -> aquí "def" se agregaría al grupo solo si aún no está allí
southerton
@southerton Sin sentido. Ya está en la piscina. Fue colocado allí por el compilador.
Marqués de Lorne
@EJP ¿por qué (e == d) es falso aquí? ambos se refieren al mismo objeto "def" en la piscina, ¿verdad?
Raja
Cadena c = nueva Cadena ("abc"); // 1 Objeto ... ¿es correcta esta declaración? Si ya se hace referencia a "abc" del grupo constante, ¿cuál es el uso del método inter?
Prashanth Debbadwar
6

Es un atajo. Originalmente no era así, pero Java lo cambió.

Estas preguntas frecuentes lo tratan brevemente. La guía de especificación de Java también habla de ello. Pero no puedo encontrarlo en línea.

Malfist
fuente
2
Enlace roto, y no tengo conocimiento de ninguna otra evidencia de que alguna vez haya cambiado.
Marqués de Lorne
1
@EJP Todavía está en la máquina de retorno si eso es útil.
Arjan
6

La cadena está sujeta a un par de optimizaciones (a falta de una frase mejor). Tenga en cuenta que String también tiene una sobrecarga de operadores (para el operador +), a diferencia de otros objetos. Así que es un caso muy especial.

Brian Agnew
fuente
1
El + es en realidad un operador que se traduce en una llamada StringBuilder.append (..).
whiskeysierra
5

Por lo general, usamos literales de cadena para evitar la creación de objetos innecesarios. Si usamos un nuevo operador para crear un objeto String, entonces creará un nuevo objeto cada vez.

Ejemplo:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

Para el código anterior en la memoria:

ingrese la descripción de la imagen aquí

Joby Wilson Mathews
fuente
2

En Java, las cadenas son un caso especial, con muchas reglas que se aplican solo a las cadenas. Las comillas dobles hacen que el compilador cree un objeto String. Dado que los objetos String son inmutables, esto permite al compilador internar múltiples cadenas y construir un grupo de cadenas más grande. Dos constantes String idénticas siempre tendrán la misma referencia de objeto. Si no desea que este sea el caso, puede usar new String (""), y eso creará un objeto String en tiempo de ejecución. El método intern () solía ser común, para hacer que las cadenas creadas dinámicamente se compararan con la tabla de búsqueda de cadenas. Una vez que una cadena está internada, la referencia del objeto apuntará a la instancia canónica de String.

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

Cuando el cargador de clases carga una clase, todas las constantes de cadena se agregan al grupo de cadenas.

Brianegge
fuente
"Las comillas dobles hacen que el compilador cree un objeto String". comentario infravalorado
csguy
0

Azúcar sintáctica. los

String s = new String("ABC");

la sintaxis todavía está disponible.

Seva Alekseyev
fuente
1
Esto no es del todo correcto. s = new String ("ABC") no le dará los mismos resultados que s = "ABC". Vea el comentario de danben.
Steve B.
2
Además, irónicamente, primero creará una instancia de String que represente "ABC" en línea, y luego la pasará como un argumento a la llamada al constructor que creará un retorno de String de valor idéntico.
Andrzej Doyle
1
El caso de uso válido para este constructor es String small = new String(huge.substring(int, int));, que le permite reciclar el gran subyacente char[]del hugeString original .
Pascal Thivent
1
@PascalThivent sí, pero ya no con Java 8. Ya no comparte matrices (en preparación para otras optimizaciones como la deduplicación automática de cadenas con G1 o la próxima compresión de cadenas).
eckes
@AndrzejDoyle No es correcto. El compilador crea el objeto para el literal.
Marqués de Lorne
0

Todavía puede usar new String("string"), pero sería más difícil crear nuevas cadenas sin literales de cadena ... tendría que usar matrices de caracteres o bytes :-) Los literales de cadena tienen una propiedad adicional: todos los mismos literales de cadena desde cualquier punto de clase a la misma cadena instancia (están internados).

Peter Štibraný
fuente
0

Casi no hay necesidad de crear una cadena nueva, ya que el literal (los caracteres entre comillas) ya es un objeto String creado cuando se carga la clase de host. Es perfectamente legal invocar métodos en un literal y don, la principal distinción es la conveniencia que proporcionan los literales. Sería un gran dolor y una pérdida de tiempo si tuviéramos que crear una matriz de caracteres y rellenarla char por char y hacer un nuevo String (matriz de caracteres).

mP.
fuente
0

Siéntase libre de crear una nueva cadena con

String s = new String("I'm a new String");

La notación habitual s = "new String";es más o menos un atajo conveniente, que debe usarse por razones de rendimiento, excepto en esos casos bastante raros, en los que realmente necesita cadenas que califiquen para la ecuación

(string1.equals(string2)) && !(string1 == string2)

EDITAR

En respuesta al comentario: esto no pretendía ser un consejo, sino solo una respuesta directa a la tesis de los interrogadores, que no usamos la palabra clave 'nueva' para Strings, que simplemente no es verdad. Espero que esta edición (incluida la anterior) aclare esto un poco. Por cierto, hay un par de respuestas buenas y mucho mejores a la pregunta anterior sobre SO.

Andreas Dolk
fuente
4
-1 - Mal consejo. NO debe "sentirse libre" de usar A new String(...)MENOS QUE su aplicación REQUIERA que cree una Cadena con una identidad distinta.
Stephen C
1
Yo sé eso. Editó la publicación para aclarar.
Andreas Dolk
0

El grupo literal contiene las cadenas que se crearon sin usar la palabra clave new.

Hay una diferencia: la cadena sin nueva referencia se almacena en el grupo literal de cadena y la cadena con nueva dice que están en la memoria del montón.

Las cadenas con new están en otra parte de la memoria como cualquier otro objeto.

lavina
fuente
0

Porque String es una clase inmutable en java.

Ahora bien, ¿por qué es inmutable? Como String es inmutable, puede compartirse entre varios subprocesos y no necesitamos sincronizar la operación de String externamente. As String también se usa en el mecanismo de carga de clases. Entonces, si String era mutable, java.io.writer podría haberse cambiado a abc.xyz.mywriter

Mr37037
fuente
0
TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

Salida:

Cierto

Creé dos objetos separados, ambos tienen un campo (ref) 'Nombre'. Entonces, incluso en este caso, se comparte "Jan Peter", si entiendo la forma en que Java se ocupa ...

Pete Del Fina
fuente
0

Bueno, StringPool se implementa usando The Hashmap en java. Si estamos creando siempre con una nueva palabra clave, no está buscando en String Pool y creando una nueva memoria para ella que podría ser necesaria más adelante si tenemos una operación de memoria intensiva en ejecución y si estamos creando todas las cadenas con una nueva palabra clave que afectaría el rendimiento. de nuestra aplicación. Por lo tanto, es aconsejable no usar nuevas palabras clave para crear cadenas porque solo irá al grupo de cadenas, que a su vez es un Hashmap, (memoria guardada, imagínese si tenemos muchas cadenas creadas con una nueva palabra clave) aquí se almacenará y si la cadena ya existe, su referencia (que normalmente residiría en la memoria de la pila) se devolvería a la cadena recién creada. Así que se hace para mejorar el rendimiento.

Vinay Shrivastava
fuente