regulares que programación programacion libro lenguaje interpretado historia genera fundamentos funciona float extension expresiones elementos ejemplos ejemplo desde concepto compilado como codigos cero caracteristicas java compilation javac bytecode

que - ¿Por qué una clase Java compila de manera diferente con una línea en blanco?



que es java (4)

Además de los detalles del número de línea para la depuración, su manifiesto también puede almacenar la fecha y la hora de construcción. Esto naturalmente será diferente cada vez que compiles.

Tengo la siguiente clase de Java

public class HelloWorld { public static void main(String []args) { } }

Cuando compilo este archivo y ejecuto un sha256 en el archivo de clase resultante, obtengo

9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class

Luego modifiqué la clase y agregué una línea en blanco como esta:

public class HelloWorld { public static void main(String []args) { } }

Nuevamente ejecuté un sha256 en la salida esperando obtener el mismo resultado pero en vez de eso obtuve

11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class

He leído en este artículo de TutorialsPoint que:

Una línea que contiene solo espacios en blanco, posiblemente con un comentario, se conoce como una línea en blanco, y Java la ignora por completo.

Entonces, mi pregunta es que, dado que Java ignora las líneas en blanco, ¿por qué el código de bytes compilado es diferente para ambos programas?

Es decir, la diferencia en que en HelloWorld.class un byte 0x03 se reemplaza por un byte 0x04 .


Básicamente, los números de línea se guardan para la depuración, por lo que si cambia su código fuente de la manera en que lo hizo, su método comienza en una línea diferente y la clase compilada refleja la diferencia.


La suposición de que "Java ignora las líneas en blanco" es errónea. Aquí hay un fragmento de código que se comporta de manera diferente dependiendo del número de líneas vacías antes del método main :

class NewlineDependent { public static void main(String[] args) { int i = Thread.currentThread().getStackTrace()[1].getLineNumber(); System.out.println((new String[]{"foo", "bar"})[((i % 2) + 2) % 2]); } }

Si no hay líneas vacías antes de la página main , imprime "foo" , pero con una línea vacía antes de la línea main , imprime "bar" .

Dado que el comportamiento en tiempo de ejecución es diferente, los archivos .class deben ser diferentes, independientemente de las marcas de tiempo u otros metadatos.

Esto es válido para todos los idiomas que tienen acceso a los marcos de pila con números de línea, no solo para Java.

Nota: si se compila con -g:none (sin información de depuración), los números de línea no se incluirán, getLineNumber() siempre devuelve -1 , y el programa siempre imprime "bar" , independientemente del número de saltos de línea .


Puede ver el cambio utilizando javap -v que generará información detallada. Como otros ya mencionados, la diferencia estará en los números de línea:

$ javap -v HelloWorld.class > with-line.txt $ javap -v HelloWorld.class > no-line.txt $ diff -C 1 no-line.txt with-line.txt *** no-line.txt 2018-10-03 11:43:32.719400000 +0100 --- with-line.txt 2018-10-03 11:43:04.378500000 +0100 *************** *** 2,4 **** Last modified 03-Oct-2018; size 373 bytes ! MD5 checksum 058baea07fb787bdd81c3fb3f9c586bc Compiled from "HelloWorld.java" --- 2,4 ---- Last modified 03-Oct-2018; size 373 bytes ! MD5 checksum 435dbce605c21f84dda48de1a76e961f Compiled from "HelloWorld.java" *************** *** 50,52 **** LineNumberTable: ! line 3: 0 LocalVariableTable: --- 50,52 ---- LineNumberTable: ! line 4: 0 LocalVariableTable:

Más precisamente, el archivo de clase difiere en la sección LineNumberTable :

El atributo LineNumberTable es un atributo opcional de longitud variable en la tabla de atributos de un atributo de Código (§4.7.3). Puede ser utilizado por los depuradores para determinar qué parte de la matriz de códigos corresponde a un número de línea dado en el archivo fuente original.

Si hay varios atributos de LineNumberTable en la tabla de atributos de un atributo de Código, entonces pueden aparecer en cualquier orden.

Puede haber más de un atributo LineNumberTable por línea de un archivo de origen en la tabla de atributos de un atributo de Código. Es decir, los atributos LineNumberTable pueden representar juntos una línea determinada de un archivo de origen y no necesitan ser uno a uno con las líneas de origen.