Un juego de palabras con Java y Jabba. Como dice la entrada original, no falta quien se confunde, igual que con Java y JavaScript.
programación con Java
Pregunta Java: dos hilos y una variable compartida
Piensa la respuesta antes de abrirla. Todas las opciones parecen razonables, y casi siempre hay un detalle que lo cambia todo.
Pregunta Java · Threads
¿Cuál es el resultado de ejecutar el siguiente código? ¿Y por qué?
public class Prueba extends Thread {
static String cadena = "hola";
public static void main(String argv[]) {
Prueba t = new Prueba();
t.inicia(cadena);
System.out.println(cadena);
}
public void inicia(String aux) {
cadena = aux + " mundo ";
start();
}
public void run() {
for (int i=0; i<4; i++) { cadena = cadena + " " + i; }
}
}- imprime
"hola mundo" - imprime
"hola mundo 0 1 2 3" - El resultado es impredecible.
Ver la respuesta
Respuesta: 3.
300 ejecuciones, contadas con uniq -c300 hola mundo
inicia() cambia la cadena a "hola mundo " y arranca un hilo nuevo; el hilo principal sigue y hace el println sin esperar a que el otro termine. Los dos hilos usan la misma variable estática sin ninguna sincronización, así que nada garantiza qué parte del bucle habrá hecho el segundo hilo cuando el primero imprima, ni siquiera que vea sus cambios.
¿Y la salida? En 300 ejecuciones salió siempre hola mundo : arrancar un hilo tarda bastante más que llegar al println. Pero eso es una casualidad del momento, no una garantía, y con otra máquina o con el sistema cargado podría salir otra cosa. Precisamente por eso la respuesta correcta es la 3: que un error de concurrencia no aparezca en las pruebas no significa que no exista. Para esperar al hilo se usa t.join() antes de imprimir.
Más preguntas de Java
- El orden de un HashSet
- wait() sin el monitor correcto
- start() con un argumento
- wait() fuera de synchronized
- Leer más allá del final de un archivo
- binarySearch con null
- Serializar una clase cuyo padre no es Serializable
- Clases internas anidadas
- Llamar a run() en vez de start()
- Un assert que nunca falla
- HashSet sin equals ni hashCode
- Campos transient al serializar
Pregunta publicada en 2013 y revisada en octubre de 2026. La respuesta se comprobó compilando y ejecutando el código con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.
Pregunta Java: start() con un argumento
Piensa la respuesta antes de abrirla. Todas las opciones parecen razonables, y casi siempre hay un detalle que lo cambia todo.
Pregunta Java · Threads
¿Cuál es el resultado de ejecutar el siguiente código?
public class Prueba extends Thread {
public void run() {
System.out.println("método run 1");
}
public void run(String s) {
System.out.println("método run 2");
}
public static void main(String[] args) {
new Prueba().start("hola");
}
}- imprime
"método run 1" - imprime
"método run 2" - imprime
"hola" - No compila
Ver la respuesta
Respuesta: 4.
javac Prueba.javaPrueba.java:9: error: method start in class Thread cannot be applied to given types;
new Prueba().start("hola");
^
required: no arguments
found: String
reason: actual and formal argument lists differ in length
1 errorstart() no recibe argumentos, y el compilador lo rechaza. Definir un run(String s) no cambia nada: es una sobrecarga que Thread no conoce. start() arranca un hilo nuevo y la máquina virtual llama en él al run() sin parámetros.
Si se escribe new Prueba().start();, el programa imprime método run 1. Para pasarle datos a un hilo se usa un campo o el constructor, o mejor aún, un Runnable con una lambda.
Más preguntas de Java
- El orden de un HashSet
- wait() sin el monitor correcto
- Dos hilos y una variable compartida
- wait() fuera de synchronized
- Leer más allá del final de un archivo
- binarySearch con null
- Serializar una clase cuyo padre no es Serializable
- Clases internas anidadas
- Llamar a run() en vez de start()
- Un assert que nunca falla
- HashSet sin equals ni hashCode
- Campos transient al serializar
Pregunta publicada en 2013 y revisada en octubre de 2026. La respuesta se comprobó compilando y ejecutando el código con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.
Comparar cadenas en Java: == frente a equals
¿Qué devuelven las seis expresiones de la imagen? Todo se resume en una idea: == compara si dos referencias apuntan al mismo objeto, y equals compara el contenido. Lo que lía es que, con las cadenas, a veces son el mismo objeto sin que lo parezca.
También te puede interesar
Las respuestas, ejecutadas
Este programa evalúa las seis expresiones de la imagen y unas cuantas más que ayudan a entenderlas:
import java.util.Objects;
void main() {
String variable = null;
IO.println("\"cadena\" == \"cadena\" -> " + ("cadena" == "cadena"));
IO.println("\"cadena\" == \"cad\" + \"ena\" -> " + ("cadena" == "cad" + "ena"));
String cad = "cad";
final String cadFinal = "cad";
IO.println("\"cadena\" == cad + \"ena\" -> " + ("cadena" == cad + "ena"));
IO.println("\"cadena\" == cadFinal + \"ena\" -> " + ("cadena" == cadFinal + "ena"));
IO.println("\"cadena\" == \"-cadena\".substring(1) -> " + ("cadena" == "-cadena".substring(1)));
IO.println("new String(\"cadena\") == \"cadena\" -> " + (new String("cadena") == "cadena"));
IO.println("new String(\"cadena\").equals(\"cadena\") -> " + new String("cadena").equals("cadena"));
IO.println("\"-cadena\".substring(1).intern() == \"cadena\" -> " + ("-cadena".substring(1).intern() == "cadena"));
IO.println("\"cadena\".equals(variable) -> " + "cadena".equals(variable));
IO.println("Objects.equals(variable, \"cadena\") -> " + Objects.equals(variable, "cadena"));
IO.println("\"Cadena\".equalsIgnoreCase(\"CADENA\") -> " + "Cadena".equalsIgnoreCase("CADENA"));
IO.println("\"abeja\".compareTo(\"abeto\") -> " + "abeja".compareTo("abeto"));
try {
IO.println(variable.equals("cadena"));
} catch (NullPointerException e) {
IO.println("variable.equals(\"cadena\") -> " + e);
}
}javac -g Cadenas.java java Cadenas
salida"cadena" == "cadena" -> true
"cadena" == "cad" + "ena" -> true
"cadena" == cad + "ena" -> false
"cadena" == cadFinal + "ena" -> true
"cadena" == "-cadena".substring(1) -> false
new String("cadena") == "cadena" -> false
new String("cadena").equals("cadena") -> true
"-cadena".substring(1).intern() == "cadena" -> true
"cadena".equals(variable) -> false
Objects.equals(variable, "cadena") -> false
"Cadena".equalsIgnoreCase("CADENA") -> true
"abeja".compareTo("abeto") -> -10
variable.equals("cadena") -> java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "variable" is null-g guarda los nombres de las variables locales en el .class, y por eso el último mensaje dice "variable". Si lo ejecutas directamente con java Cadenas.java sale "<local1>" en su lugar: el lanzador compila sin esa información.Por qué cada una da lo que da
| Expresión | Resultado | Por qué |
|---|---|---|
"cadena" == "cadena" | true | Los literales iguales se guardan una sola vez, en el pool de cadenas. Los dos son el mismo objeto. |
"cadena" == "cad" + "ena" | true | Es una expresión constante: el compilador une las dos partes y en el .class ya solo está "cadena". |
"cadena" == "-cadena".substring(1) | false | substring crea un objeto nuevo mientras el programa se ejecuta. Mismo texto, otro objeto. |
new String("cadena").equals("cadena") | true | equals compara los caracteres, que son los mismos. |
new String("cadena") == "cadena" | false | new siempre crea un objeto nuevo, distinto del literal. |
new String("cadena") == new String("cadena") | false | Dos new, dos objetos. |
Lo interesante está en las dos líneas que añadimos: si una de las partes es una variable normal, la concatenación ocurre al ejecutar y da un objeto nuevo (false). Si la variable es final y se inicializa con un literal, cuenta como constante y el compilador vuelve a unirlas antes de tiempo (true). Es decir, el resultado de == depende de detalles que no se ven al leer el código. Basta un cambio inocente, como quitar un final, para que una comparación que funcionaba deje de hacerlo.
Pasa lo mismo con cualquier texto que llegue de fuera: lo que se lee de un archivo, de la consola o de una petición web son objetos nuevos, aunque contengan exactamente lo mismo que un literal del programa.
La regla: equals, siempre
Para saber si dos cadenas tienen el mismo texto, equals. == solo sirve para preguntar si son el mismo objeto, y eso casi nunca es lo que quieres saber.
intern() devuelve la copia del pool, y por eso "-cadena".substring(1).intern() == "cadena" da true. Es una curiosidad que conviene conocer, pero no una forma de comparar: obliga a acordarse de llamarlo en todas partes.
Cuando la variable puede ser null
Si la variable es null, variable.equals("cadena") lanza un NullPointerException, como se ve en la última línea de la salida. Hay dos formas de evitarlo:
"cadena".equals(variable)
Poner el literal delante: un literal nunca es null, y equals(null) simplemente devuelve false.
Objects.equals(variable, "cadena")
Objects.equals sirve cuando las dos pueden ser null: devuelve true si ambas lo son y nunca lanza la excepción.
Otras comparaciones
| Para… | Se usa | Ejemplo |
|---|---|---|
| Mismo texto | a.equals(b) | true / false |
| Mismo texto, con posibles null | Objects.equals(a, b) | true / false |
| Sin importar mayúsculas | a.equalsIgnoreCase(b) | "Cadena" y "CADENA" → true |
| Ordenar | a.compareTo(b) | negativo, cero o positivo: "abeja" va antes que "abeto" → -10 |
El -10 de compareTo no es una distancia con significado: es la diferencia entre la primera pareja de caracteres que no coinciden (j y t). Lo único que importa es el signo.
Entrada publicada en 2013 y revisada en octubre de 2026. Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio; las salidas están copiadas de esa ejecución.