Ao usar o mesmo JDK (ou seja, o mesmo javac
executável), os arquivos de classe gerados são sempre idênticos? Pode haver uma diferença dependendo do sistema operacional ou hardware ? Exceto na versão JDK, poderia haver algum outro fator resultando em diferenças? Existem opções do compilador para evitar diferenças? Existe uma diferença apenas em teoria ou o Oracle javac
realmente produz arquivos de classe diferentes para a mesma entrada e opções de compilador?
Atualização 1 Estou interessado na geração , ou seja, saída do compilador, não se um arquivo de classe pode ser executado em várias plataformas.
Atualização 2 Por 'Mesmo JDK', também quero dizer o mesmo javac
executável.
Atualização 3 Distinção entre diferença teórica e diferença prática em compiladores Oracle.
[EDITAR, adicionando a questão parafraseada]
"Quais são as circunstâncias em que o mesmo executável javac, quando executado em uma plataforma diferente, produzirá bytecode diferente?"
fonte
Respostas:
Vamos colocar desta forma:
Posso produzir facilmente um compilador Java totalmente compatível que nunca produz o mesmo
.class
arquivo duas vezes, dado o mesmo.java
arquivo.Eu poderia fazer isso ajustando todos os tipos de construção de bytecode ou simplesmente adicionando atributos supérfluos ao meu método (o que é permitido).
Dado que a especificação não exige que o compilador produza arquivos de classe idênticos byte a byte, eu evitaria depender de tal resultado.
No entanto , as poucas vezes que eu verificados, compilando o mesmo arquivo de origem com o mesmo compilador com as mesmas opções (e as mesmas bibliotecas!) Fez resultar no mesmo
.class
arquivos.Atualização: recentemente tropecei neste interessante post de blog sobre a implementação do
switch
emString
no Java 7 . Nesta postagem do blog, existem algumas partes relevantes, que citarei aqui (grifo meu):Isso ilustra muito claramente o problema: o compilador não é obrigado a agir de maneira determinística, desde que corresponda às especificações. Os desenvolvedores do compilador, entretanto, percebem que geralmente é uma boa idéia tentar (desde que não seja muito caro, provavelmente).
fonte
Não há nenhuma obrigação para os compiladores de produzir o mesmo bytecode em cada plataforma. Você deve consultar o
javac
utilitário dos diferentes fornecedores para obter uma resposta específica.Vou mostrar um exemplo prático disso com a ordenação de arquivos.
Digamos que temos 2 arquivos jar:
my1.jar
eMy2.jar
. Eles são colocados nolib
diretório, lado a lado. O compilador lê-os em ordem alfabética (desde que sejalib
), mas a ordem émy1.jar
,My2.jar
quando o sistema de arquivos não diferencia maiúsculas de minúsculas eMy2.jar
,my1.jar
se for sensível a maiúsculas e minúsculas.O
my1.jar
tem uma classeA.class
com um métodoO
My2.jar
tem o mesmoA.class
, mas com assinatura de método diferente (aceitaObject
):É claro que se você tiver uma chamada
ele irá compilar uma chamada de método com assinatura diferente em casos diferentes. Portanto, dependendo da sensibilidade de caixa do seu sistema de arquivos, você obterá classes diferentes como resultado.
fonte
javac
não é o mesmo, porque você tem binários diferentes em cada plataforma (por exemplo, Win7, Linux, Solaris, Mac). Para um fornecedor, não faz sentido ter implementações diferentes, mas qualquer problema específico da plataforma pode influenciar o resultado (por exemplo, pedido de flie em um diretório (pense em seulib
diretório), endianness, etc).javac
é implementada em Java (ejavac
é apenas um iniciador nativo simples), portanto, a maioria das diferenças de plataforma não deve ter impacto.Resposta curta - NÃO
Resposta longa
Eles
bytecode
não precisam ser iguais para plataformas diferentes. É o JRE (Java Runtime Environment) que sabe exatamente como executar o bytecode.Se você passar pela especificação Java VM, saberá que não precisa ser verdade que o bytecode é o mesmo para plataformas diferentes.
Percorrendo o formato do arquivo de classe , mostra a estrutura de um arquivo de classe como
Verificando sobre a versão secundária e principal
Ler mais nas notas de rodapé
Portanto, investigar tudo isso mostra que os arquivos de classe gerados em diferentes plataformas não precisam ser idênticos.
fonte
Em primeiro lugar, não há absolutamente nenhuma garantia nas especificações. Um compilador em conformidade poderia carimbar a hora da compilação no arquivo de classe gerado como um atributo adicional (personalizado) e o arquivo de classe ainda estaria correto. No entanto, ele produziria um arquivo diferente de nível de byte em cada construção, e de maneira trivial.
Em segundo lugar, mesmo sem esses truques desagradáveis, não há razão para esperar que um compilador faça exatamente a mesma coisa duas vezes seguidas, a menos que sua configuração e sua entrada sejam idênticas nos dois casos. A especificação faz descrever o nome do arquivo fonte como um dos atributos padrão, e adicionar linhas em branco para o arquivo de origem poderia muito bem mudar a tabela de número de linha.
Em terceiro lugar, nunca encontrei qualquer diferença na construção devido à plataforma host (além daquela que era atribuível às diferenças no que estava no caminho de classe). O código que variaria com base na plataforma (ou seja, bibliotecas de código nativo) não faz parte do arquivo de classe, e a geração real do código nativo do bytecode acontece depois que a classe é carregada.
Em quarto lugar (e mais importante), cheira a um mau cheiro de processo (como um cheiro de código, mas para como você age no código) querer saber disso. Versão da fonte, se possível, não da construção, e se você precisar fazer a versão da construção, versão no nível do componente inteiro e não em arquivos de classe individuais. De preferência, use um servidor CI (como Jenkins) para gerenciar o processo de transformar a origem em código executável.
fonte
Acredito que, se você usar o mesmo JDK, o byte code gerado será sempre o mesmo, sem relação com o harware e SO utilizado. A produção do código de byte é feita pelo compilador java, que usa um algoritmo determinístico para "transformar" o código fonte em código de byte. Portanto, a saída será sempre a mesma. Nessas condições, apenas uma atualização do código-fonte afetará a saída.
fonte
No geral, devo dizer que não há garantia de que a mesma fonte produzirá o mesmo bytecode quando compilada pelo mesmo compilador, mas em uma plataforma diferente.
Eu examinaria cenários envolvendo diferentes idiomas (páginas de código), por exemplo, Windows com suporte ao idioma japonês. Pense em personagens multibyte; a menos que o compilador sempre presuma que ele precisa oferecer suporte a todas as linguagens, ele pode otimizar para ASCII de 8 bits.
Há uma seção sobre compatibilidade binária na Especificação da linguagem Java .
fonte
Java allows you write/compile code on one platform and run on different platform.
AFAIK ; isso só será possível quando o arquivo de classe gerado em plataforma diferente for o mesmo ou tecnicamente igual, ou seja, idêntico.Editar
O que quero dizer com tecnicamente mesmo comentário é isso. Eles não precisam ser exatamente iguais se você comparar byte por byte.
Portanto, de acordo com a especificação do arquivo .class de uma classe em diferentes plataformas, não é necessário corresponder byte a byte.
fonte
Para a pergunta:
O exemplo de compilação cruzada mostra como podemos usar a opção Javac: -target version
Este sinalizador gera arquivos de classe que são compatíveis com a versão Java que especificamos ao invocar este comando. Portanto, os arquivos de classe serão diferentes dependendo dos atributos que fornecemos durante a compensação usando esta opção.
fonte
Muito provavelmente, a resposta é "sim", mas para ter uma resposta precisa, é necessário pesquisar algumas chaves ou geração de guid durante a compilação.
Não consigo me lembrar da situação em que isso ocorre. Por exemplo, para ter ID para fins de serialização, ele é codificado, ou seja, gerado pelo programador ou IDE.
PS Também JNI pode importar.
PPS eu descobri que
javac
é escrito em java. Isso significa que é idêntico em plataformas diferentes. Portanto, ele não geraria um código diferente sem um motivo. Portanto, ele pode fazer isso apenas com chamadas nativas.fonte
Existem duas questões.
Esta é uma questão teórica e a resposta é clara, sim, pode haver. Como já foi dito, a especificação não exige que o compilador produza arquivos de classe idêntica byte a byte.
Mesmo se cada compilador existente produzisse o mesmo código de bytes em todas as circunstâncias (hardware diferente, etc.), a resposta amanhã pode ser diferente. Se você nunca planeja atualizar o javac ou seu sistema operacional, pode testar o comportamento dessa versão em suas circunstâncias particulares, mas os resultados podem ser diferentes se você for, por exemplo, Java 7 Update 11 para Java 7 Update 15.
Isso é incognoscível.
Não sei se o gerenciamento de configuração é o motivo para fazer a pergunta, mas é um motivo compreensível para se preocupar. Comparar os códigos de byte é um controle legítimo de TI, mas apenas para determinar se os arquivos de classe mudaram, não para determinar se os arquivos de origem mudaram.
fonte
Eu colocaria de outra forma.
Em primeiro lugar, acho que a questão não é ser determinista:
É claro que é determinístico: a aleatoriedade é difícil de ser alcançada na ciência da computação e não há razão para um compilador introduzi-la aqui por qualquer motivo.
Em segundo lugar, se você reformulá-lo "quão semelhantes são os arquivos de bytecode para um mesmo arquivo de código-fonte?", Então Não , você não pode confiar no fato de que eles serão semelhantes .
Uma boa maneira de ter certeza disso é deixando o .class (ou .pyc no meu caso) em seu estágio git. Você perceberá que, entre os diferentes computadores de sua equipe, o git percebe alterações entre os arquivos .pyc, quando nenhuma alteração foi trazida para o arquivo .py (e .pyc recompilado de qualquer maneira).
Pelo menos foi o que observei. Portanto, coloque * .pyc e * .class no seu .gitignore!
fonte