Computación por dentro Tema 4
Cómo se ejecuta un programa
La CPU no entiende Java. Solo entiende código máquina: instrucciones muy pequeñas escritas en binario. Entre lo que tú escribes y lo que la CPU ejecuta siempre hay una traducción.
Lo que hace la CPU: buscar, entender, ejecutar#
Una instrucción de código máquina hace muy poco: «suma estos dos números», «copia este valor a la memoria», «salta a la instrucción 20». La CPU repite siempre los mismos tres pasos:
- Buscar: trae de la RAM la siguiente instrucción.
- Entender: mira qué tiene que hacer.
- Ejecutar: lo hace.
Para saber por dónde va, la CPU tiene el contador de programa: la dirección de la siguiente instrucción. Normalmente avanza de una en una; un if o un bucle lo que hacen es saltar a otra instrucción.
Una sola línea de Java puede convertirse en varias instrucciones. Lo que hace rápido al ordenador no es que cada instrucción sea lista, sino que hace miles de millones por segundo.
Compilar o interpretar#
Hay dos formas de traducir un programa al idioma de la CPU:
| Cómo es | Como si… | |
|---|---|---|
| Compilado (C, C++, Rust) | Un compilador traduce todo el programa una vez y crea un ejecutable, como un .exe | Traducir un libro entero y luego leer la traducción |
| Interpretado (Python, JavaScript) | Un intérprete traduce y ejecuta cada línea en el momento, cada vez que se usa | Un intérprete que va traduciendo mientras alguien habla |
Lo compilado suele ser más rápido. Lo interpretado, más cómodo: no hay que compilar nada antes de probar. Pero el ejecutable compilado solo sirve para un tipo de ordenador: el de Windows no funciona en un Mac.
Java: un poco de los dos#
Java hace las dos cosas, y así consigue que el mismo programa funcione en cualquier ordenador:
javaccompila tu.java, pero no a código máquina: a bytecode, un código máquina inventado para un ordenador que no existe. El resultado es el.class.- La máquina virtual de Java (JVM) lee ese bytecode y lo traduce al procesador de verdad mientras se ejecuta. Hay una JVM para Windows, otra para macOS, otra para Linux… y las tres entienden el mismo
.class.
Por eso decimos que Java se escribe una vez y funciona en todas partes. Y para que no sea lento, la JVM se fija en qué trozos se repiten mucho y los compila a código máquina sobre la marcha.
Ver el bytecode#
El bytecode se puede ver con javap -c, que viene con Java. Con este programa:
public class Suma {
public static void main(String[] args) {
int a = 2;
int b = 3;
int c = a + b;
System.out.println(c);
}
}javac Suma.java
javap -c SumaEsta es la parte del main (sin los comentarios que javap añade a la derecha):
0: iconst_2
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: getstatic #7
11: iload_3
12: invokevirtual #13
15: returnNo hace falta entenderlo entero. Fíjate en que int c = a + b; se ha convertido en cuatro instrucciones: carga a (iload_1), carga b (iload_2), súmalos (iadd) y guarda el resultado en c (istore_3). Los números de la izquierda son las posiciones por las que va avanzando el contador de programa.
Nota
Abre cualquier .class con un editor hexadecimal y verás que todos empiezan por los mismos cuatro bytes: CA FE BA BE. Es la marca que pusieron los creadores de Java para reconocer sus ficheros.
Errores frecuentes#
| Lo que pasa | Por qué | Solución |
|---|---|---|
javac no se reconoce como comando | El JDK no está instalado, o la terminal no lo encuentra | Mira Preparar el ordenador en los apuntes de Java |
UnsupportedClassVersionError | El .class se compiló con un Java más nuevo que el que lo ejecuta | Ejecuta con la misma versión de Java con la que compilaste, o una más nueva |
| Cambio el código y se sigue ejecutando lo de antes | Se está ejecutando el .class viejo: no has vuelto a compilar | Compila otra vez con javac antes de ejecutar (VS Code lo hace solo al darle a Run) |
Could not find or load main class | Ejecutas java en una carpeta donde no está el .class, o con el nombre mal | Ejecuta en la carpeta del .class y escribe el nombre de la clase sin .class: java Suma |