Práctica 1.3: Código intermedio y máquina virtual Java
P14 - Código intermedio y máquina virtual Java¶
En esta práctica escribirás una suma sencilla en Java, generarás el archivo .class con javac, lo ejecutarás mediante la JVM e inspeccionarás sus instrucciones con javap. Así podrás reconocer qué cambia entre el código fuente y el bytecode, y por qué la portabilidad requiere un entorno de ejecución compatible. La actividad desarrolla el apartado 1.3. Código intermedio y se centra en el CE 1.d. Tiempo estimado: 60-75 minutos; la comprobación en otro sistema es una ampliación de unos 15 minutos.
1. Objetivos¶
- Generar bytecode Java a partir de un archivo fuente y reconocer el papel de
javac,.classy la JVM. - Ejecutar el mismo programa mediante la JVM e inspeccionar algunas instrucciones de bytecode con
javap. - Explicar qué aporta la portabilidad y qué requisitos de versión, entorno de ejecución y dependencias siguen siendo necesarios.
- Identificar prácticas de trabajo reutilizables en otros procesos de compilación y construcción de software.
2. Relación con RA y criterios de evaluación¶
| Código | Descripción |
|---|---|
| RA 1 | Reconoce los elementos y herramientas que intervienen en el desarrollo de un programa informático, analizando sus características y las fases en las que actúan hasta llegar a su puesta en funcionamiento. |
| CE 1.d | Se han reconocido las características de la generación de código intermedio para su ejecución en máquinas virtuales. |
El criterio principal es CE 1.d: la actividad hace visible la generación de bytecode y su ejecución en una máquina virtual, en vez de limitarse a describir esos conceptos.
3. Requisitos y recursos¶
- Un ordenador con terminal o consola y un JDK instalado. Se recomienda JDK 17 o posterior, con
java,javacyjavapdisponibles en elPATH. - Un editor de texto o un IDE. El IDE es opcional; utilizar la terminal permite ver las órdenes y los archivos generados en cada paso.
- La teoría 1.3. Código intermedio. Como repaso, puedes consultar 1.2. Código fuente, objeto y ejecutable.
- Trabajo individual o en grupos de 2-3 personas. Si trabajáis en grupo, repartid los papeles de edición, ejecución de comandos y registro de evidencias, y cambiadlos durante la actividad.
Un compilador en línea puede servir para escribir y ejecutar el ejemplo, pero algunos servicios ocultan el .class o no incluyen javap. Para completar la inspección del bytecode, utiliza un JDK local o un entorno que permita acceder a esos archivos y herramientas.
4. Pasos a seguir¶
4.1. Preparar el entorno y escribir el código fuente¶
-
Crea una carpeta para la práctica y abre una terminal en ella. Comprueba qué herramientas tienes instaladas y registra sus versiones:
Si alguna orden no se reconoce, verifica que has instalado un JDK y que su carpeta de herramientas está en el
PATH. Anota también el sistema operativo y su versión. -
Crea un archivo llamado exactamente
Suma.javacon este programa. El nombre del archivo coincide con el de la clase pública:public class Suma { public static void main(String[] args) { int num1 = 5; int num2 = 7; int resultado = num1 + num2; System.out.println("El resultado es: " + resultado); } }Antes de continuar, predice qué mostrará el programa.
Suma.javaes el código fuente: un archivo de texto que puedes leer y modificar, pero que la CPU no ejecuta directamente como instrucciones nativas.
4.2. Compilar para generar bytecode¶
-
Desde la carpeta que contiene
Suma.java, ejecuta:Si la compilación termina sin errores, normalmente no verás ningún mensaje. Comprueba que aparece
Suma.class. Si hay un diagnóstico, léelo completo y corrige el problema antes de seguir. -
Distingue los dos archivos:
Suma.javaes el código fuente;Suma.classcontiene bytecode para la JVM. El archivo.classno es un ejecutable nativo que puedas iniciar directamente desde el sistema operativo.
4.3. Ejecutar el bytecode en la JVM¶
-
En la misma carpeta, solicita a la herramienta
javaque cargue la clase y ejecute su métodomain:Comprueba que la salida es:
-
Explica el recorrido observado:
javactransforma el fuente en bytecode y la JVM carga y ejecuta ese bytecode. Una implementación de JVM puede interpretarlo y/o compilar partes a código nativo con JIT; no des por hecho que todas las JVM utilizan internamente una única estrategia.
4.4. Inspeccionar las instrucciones de bytecode¶
-
Ejecuta
javappara mostrar una representación legible de las instrucciones:Localiza en la salida el método
mainy alguna instrucción relacionada con los valores numéricos, la suma —por ejemploiadd— y la llamada que muestra el resultado. La salida puede variar según la versión de Java y el compilador;javapmuestra bytecode, no el código fuente ni las instrucciones nativas concretas de tu CPU. -
Anota qué información puedes deducir de la salida y cuál no: las instrucciones permiten reconocer operaciones del programa, pero no describen por sí solas la plataforma física donde se ejecutará el bytecode.
4.5. Modificar el fuente y repetir el proceso¶
-
Cambia los valores de
num1ynum2a17y25. Antes de ejecutar nada, predice el resultado y explica por qué el archivo.classanterior todavía representa la versión previa del programa. -
Guarda los cambios, vuelve a compilar y ejecuta otra vez:
Comprueba que aparece
El resultado es: 42. Si no coincide, revisa el archivo guardado, los valores, la carpeta desde la que ejecutas las órdenes y si has repetido la compilación.
4.6. Portabilidad y prácticas de trabajo reutilizables¶
-
Explica si bastaría con copiar
Suma.classa otro equipo para ejecutarlo. Incluye las condiciones que deben cumplirse: debe haber una JVM compatible con la versión del bytecode y estar disponibles las bibliotecas y demás dependencias necesarias. Como ampliación, copia el.classa otro sistema operativo con una JVM compatible e intenta ejecutarjava Sumasin llevar el archivo fuente ni recompilarlo. Registra el resultado o el motivo por el que no has podido hacer la prueba. -
Identifica al menos cuatro prácticas generales de trabajo que te sirvan también en otras herramientas o lenguajes. Puedes partir de estas ideas y justificarlas con lo que has hecho:
- comprobar las versiones de las herramientas y el entorno de destino;
- separar el código fuente de los artefactos generados y conservar la fuente como referencia;
- registrar las órdenes y comprobar el resultado de cada etapa antes de avanzar;
- leer los diagnósticos completos y corregir el origen del problema, no solo ocultar el mensaje;
- repetir la construcción después de cambiar el fuente y evitar confundir un artefacto antiguo con uno recién generado;
- verificar los requisitos de ejecución y no confundir portabilidad con ausencia de dependencias.
5. Comprobaciones de finalización¶
- Has registrado las versiones de Java y del compilador y sabes qué sistema operativo utilizas.
- El archivo
Suma.javacompila sin errores y se generaSuma.class. java SumamuestraEl resultado es: 12; tras cambiar los operandos y volver a compilar, muestraEl resultado es: 42.- Has ejecutado
javap -c Sumay puedes señalar instrucciones de bytecode sin presentarlas como código fuente o código máquina nativo. - Puedes explicar la relación entre fuente, bytecode, JVM y plataforma, así como las condiciones que limitan la portabilidad.
- Has identificado y justificado al menos cuatro prácticas generales de trabajo y conservas las evidencias solicitadas.
6. Ejercicios y entregables¶
- 1.a. Completa una tabla con
Suma.java,Suma.class,javac,java,javapy la JVM.- 1.a.1. ¿Qué representa o hace cada elemento?
- 1.a.2. ¿En qué momento interviene cada elemento?
- 1.a.3. ¿Cuál es código fuente, cuál es bytecode, cuáles son herramientas y cuál es el entorno de ejecución?
- Responde con tus palabras:
- 2.a. ¿Qué diferencia hay entre el código fuente y el bytecode de
Suma? - 2.b. ¿Qué hace
javacy qué hace la herramientajava? - 2.c. ¿Por qué no se ejecuta
Suma.classdirectamente haciendo doble clic o escribiendo su nombre como si fuera un programa nativo? - 2.d. ¿Qué representa
iadden la salida dejavap -c?- 2.d.1. ¿Por qué esa salida no es código máquina de tu procesador?
- 2.e. ¿Qué aporta la JVM a la portabilidad?
- 2.e.1. ¿Qué debe seguir siendo compatible en el equipo de destino?
- 2.f. Compara este proceso con la compilación nativa habitual de C o C++.
- 2.f.1. ¿Qué artefacto se distribuye en cada caso?
- 2.f.2. ¿Qué tendrías que comprobar para ejecutar el programa en otro sistema?
- 2.a. ¿Qué diferencia hay entre el código fuente y el bytecode de
- 3.a. Cambia los operandos a
17y25.- 3.a.1. Antes de ejecutar, incluye tu predicción del resultado.
- 3.a.2. ¿Qué salida obtienes al ejecutar?
- 3.a.3. Explica qué ocurriría si editases
Suma.javapero ejecutases el.classantiguo sin recompilar. - 3.b. Guarda el fuente, vuelve a compilarlo con
javacy ejecuta la clase actualizada conjava Suma. Registra las órdenes. En este flujo no se usa un comando de enlazado separado como en la práctica de GCC; la JVM carga, verifica y resuelve las clases durante la ejecución.
- 4.a. Enumera al menos cuatro prácticas generales de trabajo observadas en la actividad y explica cómo ayudan a evitar errores o a reproducir el proceso.
- 5.a. Entrega
Suma.javay unREADME.mdidentificado con tu nombre, módulo, unidad y práctica. Incluye las versiones del entorno, las órdenes utilizadas, la tabla, las respuestas, una captura o transcripción de las dos ejecuciones, un fragmento dejavap -cy la reflexión sobre las prácticas generales. Adjunta tambiénSuma.classo, si el aula no admite archivos binarios, una evidencia verificable de su generación. - 6.a. (Ampliación opcional) Intenta ejecutar el mismo
Suma.classen otro sistema operativo o equipo. Indica qué archivos copiaste, la versión de JVM disponible y si hubo algún requisito de versión o dependencia que afectase al resultado. La prueba en otro sistema es opcional.
7. Solución orientativa¶
El programa inicial genera Suma.class al ejecutarse javac Suma.java; java Suma carga la clase mediante una JVM y muestra El resultado es: 12. javap -c Suma presenta instrucciones de bytecode; entre ellas se puede reconocer la suma entera mediante iadd, aunque la secuencia exacta y sus índices dependen de la versión y del compilador. Después de cambiar los operandos a 17 y 25, hay que volver a compilar y la salida debe ser El resultado es: 42. La portabilidad depende de una JVM que admita la versión de clase, además de las bibliotecas y dependencias requeridas. Encontrarás respuestas ampliadas en la solución orientativa de la práctica P14.