Inmutabilidad de String y el pool de cadenas
Comprenda por qué los objetos String son inmutables, cómo funciona el pool de cadenas y cuándo usar == frente a equals.
Inmutabilidad de String y el pool de cadenas es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
Inmutabilidad de String y el pool de cadenas
Las cadenas son inmutables en Java. Comprender la inmutabilidad, el pool de cadenas y la igualdad de referencias frente a la igualdad de valores evita errores sutiles.
Por qué las cadenas son inmutables
Los objetos String no se pueden modificar después de su creación. Cualquier operación que «cambie» un String en realidad crea un objeto String nuevo. Esto permite compartir objetos, garantizar la seguridad en entornos concurrentes y almacenar en caché el hashCode.
String s = "hello";
s.toUpperCase(); // creates a new String, does NOT modify s
System.out.println(s); // still "hello"
String upper = s.toUpperCase(); // must capture the result
System.out.println(upper); // HELLOEl pool de cadenas (interning)
Los literales de String se almacenan en el pool de cadenas (una sección especial del heap). Dos literales con el mismo contenido comparten el mismo objeto.
String a = "hello"; // goes into pool
String b = "hello"; // same object from pool
String c = new String("hello"); // forces new object outside pool
System.out.println(a == b); // true (same pool reference)
System.out.println(a == c); // false (different objects)
System.out.println(a.equals(c)); // true (same content)== frente a equals()
Utilice siempre .equals() para comparar el contenido de un String. El operador == comprueba si dos variables apuntan al mismo objeto (igualdad de referencias).
String input = new String("admin"); // from user input, not pooled
String role = "admin";
// Dangerous: fails because different objects
if (input == role) System.out.println("Same"); // not printed!
// Correct: compares content
if (input.equals(role)) System.out.println("Equal!"); // prints
// Null-safe: put constant first to avoid NPE
if ("admin".equals(input)) System.out.println("Admin"); // printsintern(): incorporar manualmente un String al pool
String.intern() fuerza la incorporación de un String al pool y devuelve la referencia almacenada en el pool. Rara vez se necesita en las versiones modernas de Java.
String s1 = new String("interned");
String s2 = s1.intern();
String s3 = "interned"; // already in pool
System.out.println(s2 == s3); // true (both point to pool)
System.out.println(s1 == s3); // false (s1 is off-pool)
// Modern use: prefer String.intern() only when you need
// identity-based caching with thousands of repeated stringsComportamiento de la concatenación de String
La concatenación con + crea objetos String nuevos. Dentro de un bucle, esto tiene una complejidad O(n²). El compilador optimiza las expresiones individuales, pero no la concatenación basada en bucles.
// Compiler optimizes this to a StringBuilder automatically:
String result = "Hello, " + "World" + "!";
// In loops: compiler does NOT optimize — use StringBuilder explicitly!
List<String> words = List.of("a", "b", "c", "d");
String bad = ""; // O(n^2) — new object each iteration
for (String w : words) bad += w;
StringBuilder sb = new StringBuilder();
for (String w : words) sb.append(w); // O(n) — efficient
String good = sb.toString();
System.out.println(good); // abcdComparar cadenas correctamente
Utilice siempre equals(); para comparar sin distinguir mayúsculas de minúsculas, utilice equalsIgnoreCase(). Utilice compareTo() para el orden lexicográfico.
String a = "Java";
String b = "java";
System.out.println(a.equals(b)); // false
System.out.println(a.equalsIgnoreCase(b)); // true
System.out.println(a.compareToIgnoreCase(b)); // 0 (equal)
System.out.println(a.compareTo(b)); // negative (J < j in Unicode)Caché del hashCode de String
Como las cadenas son inmutables, Java almacena en caché el hashCode después de la primera llamada. Las llamadas posteriores devuelven el valor almacenado en caché, lo que hace que las cadenas sean muy eficientes como claves de HashMap.
String key = "product:12345";
// hashCode computed once and cached:
int h1 = key.hashCode();
int h2 = key.hashCode(); // returns cached value
System.out.println(h1 == h2); // true
// Strings are ideal HashMap keys because:
// 1. hashCode is consistent (immutable content)
// 2. hashCode is cached (fast repeated lookups)
// 3. equals is well-defined (content-based)
Map<String, Integer> map = new HashMap<>();
map.put("key", 42);
System.out.println(map.get("key")); // 42String es final
La clase String es final: no se puede crear una subclase de ella. Esto garantiza que ninguna subclase pueda romper la inmutabilidad ni la coherencia del hashCode.
// String is final — this will not compile:
// class MutableString extends String {} // compile error
// You cannot override String behavior.
// If you need custom string-like behavior, use a wrapper:
record ProductSku(String value) {
ProductSku { if (!value.matches("[A-Z]{3}-[0-9]{4}")) throw new IllegalArgumentException(); }
@Override public String toString() { return value; }
}String.format frente a la concatenación
Para cadenas formadas por varias partes, prefiera String.format() o los bloques de texto a la concatenación, ya que ofrecen mayor claridad y facilitan la localización.
String name = "Alice";
int age = 30;
double score = 97.5;
// Concatenation — harder to read with many parts
String bad = "User: " + name + ", Age: " + age + ", Score: " + score;
// String.format — clear placeholders
String good = String.format("User: %s, Age: %d, Score: %.1f", name, age, score);
System.out.println(good);
// User: Alice, Age: 30, Score: 97.5Operaciones con String seguras frente a null
Muchas operaciones de String lanzan una NPE si la cadena es null. Utilice patrones defensivos o String.valueOf() para gestionar null de forma segura.
String value = null;
// Null-safe length check
int len = (value != null) ? value.length() : 0;
System.out.println(len); // 0
// Null-safe comparison (put constant first)
boolean isAdmin = "admin".equals(value); // false, no NPE
// String.valueOf converts null to "null" string
System.out.println(String.valueOf(value)); // "null"
System.out.println(Objects.toString(value, "default")); // "default"Comprobación rápida
¿Qué imprime el siguiente código?
String a = "hello";
String b = new String("hello");
System.out.println(a.equals(b));
System.out.println(a == b);Resumen: inmutabilidad de String y el pool de cadenas
Conclusiones principales:
- Las cadenas son inmutables: las operaciones devuelven objetos String nuevos y nunca modifican el original
- Los literales de String se almacenan en un pool: dos literales con el mismo contenido comparten un objeto
- Utilice siempre .equals() para comparar el contenido de un String; == compara las referencias de los objetos
- Utilice equalsIgnoreCase() para las comparaciones que no distinguen mayúsculas de minúsculas
- La concatenación de cadenas en bucles tiene una complejidad O(n²): utilice StringBuilder para mejorar la eficiencia
- Las cadenas almacenan en caché su hashCode, lo que las hace eficientes y seguras como claves de HashMap
Preguntas frecuentes
¿La lección «Inmutabilidad de String y el pool de cadenas» es gratis?
Sí — el texto completo de «Inmutabilidad de String y el pool de cadenas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Inmutabilidad de String y el pool de cadenas»?
Comprenda por qué los objetos String son inmutables, cómo funciona el pool de cadenas y cuándo usar == frente a equals. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Inmutabilidad de String y el pool de cadenas»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Inmutabilidad de String y el pool de cadenas
- StringBuilder para una concatenación eficiente
- Bloques de texto y String.format
- Expresiones regulares con Pattern y Matcher