Cuando se usa el mismo JDK (es decir, el mismo javac
ejecutable), ¿los archivos de clases generados son siempre idénticos? ¿Puede haber alguna diferencia según el sistema operativo o el hardware ? Excepto en la versión JDK, ¿podría haber otros factores que generen diferencias? ¿Hay opciones de compilador para evitar diferencias? ¿Es posible una diferencia solo en teoría o Oracle javac
realmente produce archivos de clases diferentes para las mismas opciones de entrada y compilador?
Actualización 1 Me interesa la generación , es decir, la salida del compilador, no si un archivo de clase se puede ejecutar en varias plataformas.
Actualización 2 Por 'Mismo JDK', también me refiero al mismo javac
ejecutable.
Actualización 3 Distinción entre diferencia teórica y diferencia práctica en los compiladores de Oracle.
[EDITAR, agregando una pregunta parafraseada]
"¿Cuáles son las circunstancias en las que el mismo ejecutable javac, cuando se ejecuta en una plataforma diferente, producirá un código de bytes diferente?"
fuente
Respuestas:
Pongámoslo de esta manera:
Puedo producir fácilmente un compilador de Java totalmente conforme que nunca produce el mismo
.class
archivo dos veces, dado el mismo.java
archivo.Podría hacer esto ajustando todo tipo de construcción de código de bytes o simplemente agregando atributos superfluos a mi método (que está permitido).
Dado que la especificación no requiere que el compilador produzca archivos de clase idénticos byte por byte, evitaría depender tal resultado.
Sin embargo , las pocas veces que he comprobado, compilar el mismo archivo fuente con el mismo compilador con los mismos conmutadores (¡y las mismas bibliotecas!) Dieron como resultado el mismo
.class
archivos.Actualización: Recientemente me encontré con esta interesante publicación de blog sobre la implementación de
switch
onString
en Java 7 . En esta publicación de blog, hay algunas partes relevantes, que citaré aquí (énfasis mío):Esto ilustra bastante claramente el problema: no se requiere que el compilador actúe de manera determinista, siempre que coincida con la especificación. Sin embargo, los desarrolladores del compilador se dan cuenta de que, en general, es una buena idea intentarlo (siempre que no sea demasiado caro, probablemente).
fuente
Los compiladores no tienen la obligación de producir el mismo código de bytes en cada plataforma. Debe consultar la
javac
utilidad de los diferentes proveedores para tener una respuesta específica.Mostraré un ejemplo práctico de esto con la ordenación de archivos.
Digamos que tenemos 2 archivos jar:
my1.jar
yMy2.jar
. Se colocan en ellib
directorio, uno al lado del otro. El compilador los lee en orden alfabético (ya que es asílib
), pero el orden esmy1.jar
,My2.jar
cuando el sistema de archivos no distingue entre mayúsculas y minúsculas yMy2.jar
,my1.jar
si es sensible a las mayúsculas y minúsculas.El
my1.jar
tiene una claseA.class
con un métodoEl
My2.jar
tiene el mismoA.class
, pero con diferente firma del método (aceptaObject
):Está claro que si tienes una llamada
compilará una llamada a un método con una firma diferente en diferentes casos. Entonces, dependiendo de la sensibilidad de mayúsculas y minúsculas de su sistema de archivos, obtendrá una clase diferente como resultado.
fuente
javac
es lo mismo, porque tiene diferentes binarios en cada plataforma (por ejemplo, Win7, Linux, Solaris, Mac). Para un proveedor, no tiene sentido tener diferentes implementaciones, pero cualquier problema específico de la plataforma puede influir en el resultado (p. Ej., Ordenar las moscas en un directorio (piense en sulib
directorio), endianness, etc.).javac
se implementa en Java (yjavac
es solo un iniciador nativo simple), por lo que la mayoría de las diferencias de plataforma no deberían tener ningún impacto.Respuesta corta - NO
Respuesta larga
Ellos
bytecode
necesario que sean iguales para diferentes plataformas. Es el JRE (Java Runtime Environment) el que sabe exactamente cómo ejecutar el bytecode.Si pasa por la especificación Java VM , llegará a saber que esto no tiene por qué ser cierto que el código de bytes es el mismo para diferentes plataformas.
Pasando por el formato de archivo de clase , muestra la estructura de un archivo de clase como
Comprobando sobre la versión menor y mayor
Leer más a través de las notas al pie
Entonces, investigar todo esto muestra que los archivos de clase generados en diferentes plataformas no necesitan ser idénticos.
fuente
En primer lugar, no existe absolutamente tal garantía en la especificación. Un compilador conforme podría marcar la hora de compilación en el archivo de clase generado como un atributo adicional (personalizado), y el archivo de clase aún sería correcto. Sin embargo, produciría un archivo diferente a nivel de bytes en cada compilación, y de manera trivial.
En segundo lugar, incluso sin trucos tan desagradables, no hay razón para esperar que un compilador haga exactamente lo mismo dos veces seguidas a menos que tanto su configuración como su entrada sean idénticas en los dos casos. La especificación hace describir el nombre del archivo fuente como uno de los atributos estándar, y la adición de líneas en blanco al archivo de origen bien podría cambiar la tabla de números de línea.
En tercer lugar, nunca he encontrado ninguna diferencia en la compilación debido a la plataforma de host (aparte de la que se atribuye a las diferencias en lo que había en la ruta de clases). El código que variaría según la plataforma (es decir, bibliotecas de código nativo) no es parte del archivo de clase, y la generación real de código nativo a partir del código de bytes ocurre después de que se carga la clase.
En cuarto lugar (y lo más importante), apesta a un mal olor a proceso (como un olor a código, pero por cómo actúa sobre el código) querer saber esto. Versión de la fuente si es posible, no de la compilación, y si necesita versionar la compilación, la versión a nivel de componente completo y no en archivos de clases individuales. De preferencia, use un servidor CI (como Jenkins) para administrar el proceso de convertir la fuente en código ejecutable.
fuente
Creo que, si usa el mismo JDK, el código de bytes generado será siempre el mismo, sin relación con el hardware y el sistema operativo utilizado. La producción del código de bytes la realiza el compilador de Java, que utiliza un algoritmo determinista para "transformar" el código fuente en código de bytes. Entonces, la salida siempre será la misma. En estas condiciones, solo una actualización del código fuente afectará la salida.
fuente
En general, tengo que decir que no hay garantía de que la misma fuente produzca el mismo código de bytes cuando la compila el mismo compilador pero en una plataforma diferente.
Buscaría escenarios que involucren diferentes idiomas (páginas de códigos), por ejemplo, Windows con soporte para el idioma japonés. Piense en caracteres de varios bytes; a menos que el compilador siempre asuma que necesita admitir todos los lenguajes que podría optimizar para ASCII de 8 bits.
Hay una sección sobre compatibilidad binaria en la Especificación del lenguaje Java .
fuente
Java allows you write/compile code on one platform and run on different platform.
AFAIK ; esto será posible solo cuando el archivo de clase generado en una plataforma diferente sea igual o técnicamente idéntico, es decir, idéntico.Editar
Lo que quiero decir con técnicamente el mismo comentario es eso. No es necesario que sean exactamente iguales si compara byte por byte.
Entonces, según la especificación, el archivo .class de una clase en diferentes plataformas no necesita coincidir byte por byte.
fuente
Para la pregunta:
El ejemplo de compilación cruzada muestra cómo podemos usar la opción Javac: -target version
Esta bandera genera archivos de clase que son compatibles con la versión de Java que especificamos al invocar este comando. Por lo tanto, los archivos de clases diferirán según los atributos que proporcionemos durante la comparación con esta opción.
fuente
Lo más probable es que la respuesta sea "sí", pero para tener una respuesta precisa, es necesario buscar algunas claves o generación de guid durante la compilación.
No recuerdo la situación en la que ocurre esto. Por ejemplo, para tener un ID con fines de serialización, está codificado, es decir, generado por el programador o el IDE.
PD: También JNI puede importar.
PPS encontré que
javac
está escrito en java. Esto significa que es idéntico en diferentes plataformas. Por lo tanto, no generaría un código diferente sin una razón. Por lo tanto, solo puede hacer esto con llamadas nativas.fuente
Hay dos preguntas.
Esta es una pregunta teórica, y la respuesta es claramente, sí, puede haberla. Como han dicho otros, la especificación no requiere que el compilador produzca archivos de clase idénticos byte por byte.
Incluso si cada compilador que existe actualmente produce el mismo código de bytes en todas las circunstancias (hardware diferente, etc.), la respuesta mañana podría ser diferente. Si nunca planea actualizar javac o su sistema operativo, puede probar el comportamiento de esa versión en sus circunstancias particulares, pero los resultados pueden ser diferentes si pasa, por ejemplo, de Java 7 Update 11 a Java 7 Update 15.
Eso es incognoscible.
No sé si la administración de la configuración es su razón para hacer la pregunta, pero es una razón comprensible para preocuparse. Comparar códigos de bytes es un control de TI legítimo, pero solo para determinar si los archivos de clase cambiaron, no para determinar si lo hicieron los archivos fuente.
fuente
Lo diría de otra manera.
Primero, creo que la pregunta no se trata de ser determinista:
Por supuesto que es determinista: la aleatoriedad es difícil de lograr en informática, y no hay razón para que un compilador la introduzca aquí por ningún motivo.
En segundo lugar, si lo reformula con "¿qué tan similares son los archivos de código de bytes para un mismo archivo de código fuente?", Entonces No , no puede confiar en el hecho de que serán similares .
Una buena forma de asegurarse de esto es dejando el .class (o .pyc en mi caso) en su etapa de git. Se dará cuenta de que entre las diferentes computadoras de su equipo, git nota cambios entre los archivos .pyc, cuando no se introdujeron cambios en el archivo .py (y .pyc se volvió a compilar de todos modos).
Al menos eso es lo que observé. ¡Así que ponga * .pyc y * .class en su .gitignore!
fuente