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 su lugar 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, 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 0x03
byte se reemplaza por un 0x04
byte.
java
compilation
javac
bytecode
KNejad
fuente
fuente
Set
s inmutables con aleatorización internamente, podría producir un orden diferente en cada ejecución. También podría agregar un atributo personalizado que contenga el tiempo de compilación. Y así sucesivamente ...Respuestas:
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.
fuente
end-of-transmission
significa el código ASCII 4 yend-of-text
representa el código ASCII 3-g:none
indicador al compilar (que elimina toda la información de depuración, ver aquí ) y obtuve el mismo hash en ambos escenarios.Puede ver el cambio mediante el uso
javap -v
que generará información detallada. Como otros ya mencionados, la diferencia estará en los números de línea:Más precisamente, el archivo de clase difiere en la
LineNumberTable
sección:fuente
La suposición de que "Java ignora las líneas en blanco" es incorrecta. 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
:Si no hay líneas vacías antes
main
, imprime"foo"
, pero con una línea vacía antesmain
, imprime"bar"
.Dado que el comportamiento en tiempo de ejecución es diferente, los
.class
archivos 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 la pila con números de línea, no solo para Java.
Nota: si se compila con
-g:none
(sin ninguna información de depuración), los números de línea no se incluirán,getLineNumber()
siempre regresa-1
y el programa siempre imprime"bar"
, independientemente de la cantidad de saltos de línea.fuente
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
.-1
fue usando la-g:none
bandera. ¿Hay alguna otra forma de obtener esta excepción usando ordinariojavac
?-g
opción. También hay-g:vars
y-g:source
que impide la generación de laLineNumberTable
.Además de los detalles de cualquier número de línea para la depuración, su manifiesto también puede almacenar la fecha y hora de compilación. Naturalmente, esto será diferente cada vez que compile.
fuente