Lorsque vous utilisez le même JDK (c'est-à-dire le même javac
exécutable), les fichiers de classe générés sont-ils toujours identiques? Peut-il y avoir une différence selon le système d'exploitation ou le matériel ? À l'exception de la version JDK, pourrait-il y avoir d'autres facteurs entraînant des différences? Existe-t-il des options de compilation pour éviter les différences? Une différence est-elle seulement possible en théorie ou Oracle produit-il javac
réellement des fichiers de classe différents pour les mêmes options d'entrée et de compilation?
Mise à jour 1 Je suis intéressé par la génération , c'est-à-dire la sortie du compilateur, pas si un fichier de classe peut être exécuté sur différentes plates-formes.
Mise à jour 2 Par «même JDK», j'entends aussi le même javac
exécutable.
Mise à jour 3 Distinction entre différence théorique et différence pratique dans les compilateurs d'Oracle.
[EDIT, ajoutant une question paraphrasée]
"Dans quelles circonstances le même exécutable javac, lorsqu'il est exécuté sur une plate-forme différente, produira un bytecode différent?"
la source
Réponses:
Disons-le de cette façon:
Je peux facilement produire un compilateur Java entièrement conforme qui ne produit jamais
.class
deux fois le même fichier, étant donné le même.java
fichier.Je pourrais le faire en modifiant toutes sortes de construction de bytecode ou en ajoutant simplement des attributs superflus à ma méthode (ce qui est autorisé).
Étant donné que la spécification n'exige pas que le compilateur produise des fichiers de classe identiques octet par octet, j'éviterais de dépendre d' un tel résultat.
Cependant , les quelques fois que je l' ai vérifié, la compilation du même fichier source avec le même compilateur avec les mêmes commutateurs (et les mêmes bibliothèques!) Ont fait dans les mêmes
.class
fichiers.Mise à jour: Je suis récemment tombé sur cet article de blog intéressant sur l'implémentation d'
switch
onString
dans Java 7 . Dans cet article de blog, il y a quelques parties pertinentes, que je vais citer ici (c'est moi qui souligne):Cela illustre assez clairement le problème: le compilateur n'est pas obligé d'agir de manière déterministe, tant qu'il correspond à la spécification. Les développeurs du compilateur, cependant, se rendent compte que c'est généralement une bonne idée d' essayer (à condition que ce ne soit pas trop cher, probablement).
la source
Il n'y a aucune obligation pour les compilateurs de produire le même bytecode sur chaque plateforme. Vous devriez consulter l'
javac
utilitaire des différents fournisseurs pour avoir une réponse spécifique.Je vais montrer un exemple pratique pour cela avec l'ordre des fichiers.
Disons que nous avons 2 fichiers jar:
my1.jar
etMy2.jar
. Ils sont placés dans lelib
répertoire, côte à côte. Le compilateur les lit par ordre alphabétique (puisque c'est le caslib
), mais l'ordre estmy1.jar
,My2.jar
lorsque le système de fichiers est insensible à la casse, etMy2.jar
,my1.jar
s'il est sensible à la casse.A
my1.jar
une classeA.class
avec une méthodeLe
My2.jar
a le mêmeA.class
, mais avec une signature de méthode différente (accepteObject
):Il est clair que si vous avez un appel
il compilera un appel de méthode avec une signature différente dans différents cas. Ainsi, en fonction de la sensibilité à la casse de votre système de fichiers, vous obtiendrez une classe différente en conséquence.
la source
javac
n'est pas le même, car vous avez différents binaires sur chaque plate-forme (par exemple Win7, Linux, Solaris, Mac). Pour un fournisseur, cela n'a pas de sens d'avoir des implémentations différentes, mais tout problème spécifique à la plate-forme peut influencer le résultat (par exemple, le classement des fichiers dans un répertoire (pensez à votrelib
répertoire), l'endianness, etc.).javac
sont implémentés en Java (etjavac
n'est qu'un simple lanceur natif), donc la plupart des différences de plate-forme ne devraient avoir aucun impact.Réponse courte - NON
Longue réponse
Ils
bytecode
n'ont pas besoin d'être les mêmes pour différentes plates-formes. C'est le JRE (Java Runtime Environment) qui sait exactement comment exécuter le bytecode.Si vous passez par la spécification Java VM, vous saurez que cela ne doit pas être vrai que le bytecode est le même pour différentes plates-formes.
En passant par le format de fichier de classe , il montre la structure d'un fichier de classe comme
Vérification de la version mineure et majeure
Lire plus à travers les notes de bas de page
Ainsi, étudier tout cela montre que les fichiers de classe générés sur différentes plates-formes n'ont pas besoin d'être identiques.
la source
Premièrement, il n'y a absolument aucune garantie de ce type dans les spécifications. Un compilateur conforme pourrait marquer l'heure de la compilation dans le fichier de classe généré comme un attribut supplémentaire (personnalisé), et le fichier de classe serait toujours correct. Cela produirait cependant un fichier différent au niveau de l'octet sur chaque build, et cela de manière triviale.
Deuxièmement, même sans de telles astuces, il n'y a aucune raison de s'attendre à ce qu'un compilateur fasse exactement la même chose deux fois de suite à moins que sa configuration et son entrée ne soient identiques dans les deux cas. La spécification ne décrit le nom du fichier source comme l' un des attributs standard, et en ajoutant des lignes vides au fichier source pourrait bien changer la table de numéro de ligne.
Troisièmement, je n'ai jamais rencontré de différence de construction en raison de la plate-forme hôte (autre que celle qui était attribuable à des différences dans ce qui se trouvait sur le chemin de classe). Le code qui varierait en fonction de la plate-forme (c'est-à-dire les bibliothèques de code natif) ne fait pas partie du fichier de classe, et la génération réelle du code natif à partir du bytecode se produit après le chargement de la classe.
Quatrièmement (et le plus important) cela sent une mauvaise odeur de processus (comme une odeur de code, mais pour la façon dont vous agissez sur le code) de vouloir le savoir. Version la source si possible, pas la version, et si vous avez besoin de la version de la version, la version au niveau du composant entier et non sur des fichiers de classe individuels. De préférence, utilisez un serveur CI (tel que Jenkins) pour gérer le processus de transformation de la source en code exécutable.
la source
Je crois que, si vous utilisez le même JDK, le code d'octet généré sera toujours le même, sans relation avec le matériel et le système d'exploitation utilisés. La production de code d'octet est effectuée par le compilateur java, qui utilise un algorithme déterministe pour "transformer" le code source en code d'octet. Ainsi, la sortie sera toujours la même. Dans ces conditions, seule une mise à jour du code source affectera la sortie.
la source
Dans l'ensemble, je dois dire qu'il n'y a aucune garantie que la même source produira le même bytecode lorsqu'elle sera compilée par le même compilateur mais sur une plate-forme différente.
J'examinerais des scénarios impliquant différentes langues (pages de codes), par exemple Windows avec le support de la langue japonaise. Pensez aux caractères multi-octets; sauf si le compilateur suppose toujours qu'il doit prendre en charge tous les langages qu'il peut optimiser pour l'ASCII 8 bits.
Il existe une section sur la compatibilité binaire dans la spécification du langage Java .
la source
Java allows you write/compile code on one platform and run on different platform.
AFAIK ; cela ne sera possible que si le fichier de classe généré sur une plate-forme différente est identique ou techniquement identique, c'est-à-dire identique.Éditer
Ce que je veux dire par techniquement le même commentaire, c'est que. Ils n'ont pas besoin d'être exactement les mêmes si vous comparez octet par octet.
Ainsi, selon les spécifications, le fichier .class d'une classe sur différentes plates-formes n'a pas besoin de correspondre octet par octet.
la source
Pour la question:
L' exemple de compilation croisée montre comment nous pouvons utiliser l'option Javac: -target version
Cet indicateur génère des fichiers de classe compatibles avec la version Java que nous spécifions lors de l'appel de cette commande. Par conséquent, les fichiers de classe différeront en fonction des attributs que nous fournissons lors de la comparaison à l'aide de cette option.
la source
Très probablement, la réponse est "oui", mais pour avoir une réponse précise, il faut rechercher des clés ou la génération de guid lors de la compilation.
Je ne me souviens pas de la situation où cela se produit. Par exemple, pour avoir un ID à des fins de sérialisation, il est codé en dur, c'est-à-dire généré par le programmeur ou l'IDE.
PS JNI peut également compter.
PPS j'ai trouvé qui
javac
est lui-même écrit en java. Cela signifie qu'il est identique sur différentes plates-formes. Par conséquent, il ne générerait pas de code différent sans raison. Donc, il ne peut le faire qu'avec des appels natifs.la source
Il y a deux questions.
C'est une question théorique, et la réponse est clairement oui, il peut y en avoir. Comme d'autres l'ont dit, la spécification n'exige pas que le compilateur produise des fichiers de classe identiques octet par octet.
Même si chaque compilateur actuellement existant produisait le même code d'octet en toutes circonstances (matériel différent, etc.), la réponse demain pourrait être différente. Si vous ne prévoyez jamais de mettre à jour javac ou votre système d'exploitation, vous pouvez tester le comportement de cette version dans vos circonstances particulières, mais les résultats peuvent être différents si vous passez, par exemple, de Java 7 Update 11 à Java 7 Update 15.
C'est inconnaissable.
Je ne sais pas si la gestion de la configuration est votre raison de poser la question, mais c'est une raison compréhensible de s'en soucier. La comparaison des codes d'octet est un contrôle informatique légitime, mais uniquement pour déterminer si les fichiers de classe ont changé, et non pour déterminer si les fichiers source l'ont fait.
la source
Je le dirais autrement.
Premièrement, je pense que la question n'est pas d'être déterministe:
Bien sûr, il est déterministe: l'aléatoire est difficile à obtenir en informatique, et il n'y a aucune raison pour qu'un compilateur l'introduise ici pour quelque raison que ce soit.
Deuxièmement, si vous le reformulez en "dans quelle mesure les fichiers de bytecode sont-ils similaires pour un même fichier de code source?", Alors non , vous ne pouvez pas vous fier au fait qu'ils seront similaires .
Un bon moyen de s'en assurer est de laisser le .class (ou .pyc dans mon cas) dans votre étape git. Vous vous rendrez compte que parmi les différents ordinateurs de votre équipe, git remarque les changements entre les fichiers .pyc, lorsqu'aucune modification n'a été apportée au fichier .py (et .pyc recompilé de toute façon).
Du moins c'est ce que j'ai observé. Alors mettez * .pyc et * .class dans votre .gitignore!
la source