web-dev-qa-db-fra.com

Fonctionnalités de bytecode non disponibles en langage Java

Y a-t-il actuellement (Java 6) des choses que vous pouvez faire dans le bytecode Java que vous ne pouvez pas faire depuis le langage Java?

Je sais que les deux sont complets, alors lisez "peut faire" comme "peut faire beaucoup plus vite/mieux, ou simplement d'une manière différente".

Je pense à des bytecodes supplémentaires tels que invokedynamic, qui ne peuvent pas être générés à l'aide de Java, sauf que ce code est destiné à une version ultérieure.

141
Bart van Heukelom

Autant que je sache, les bytecodes pris en charge par Java 6 ne contiennent aucune fonctionnalité majeure qui ne soit pas également accessible à partir du code source Java. La raison principale en est évidemment que le bytecode Java a été conçu avec le langage Java à l’esprit.

Certaines fonctionnalités ne sont toutefois pas produites par les compilateurs Java modernes:

  • L'indicateur ACC_SUPER :

    Ceci est un drapeau qui peut être défini sur une classe et spécifie comment une casse spécifique du bytecode invokespecial est gérée pour cette classe. Il est défini par tous les compilateurs Java modernes (où "moderne" est> = Java 1.1, si je me souviens bien) et seuls les anciens compilateurs Java produisaient des fichiers de classe dans lesquels cela était non défini. Cet indicateur n'existe que pour des raisons de compatibilité ascendante. Notez que depuis Java 7u51, ACC_SUPER est complètement ignoré pour des raisons de sécurité.

  • Les bytecodes jsrret.

    Ces bytecodes ont été utilisés pour implémenter des sous-routines (principalement pour implémenter des blocs finally). Ils sont ne sont plus produits depuis Java 6 . La raison de leur dépréciation est qu’ils compliquent beaucoup la vérification statique sans grand gain (c’est-à-dire que le code qui utilise peut presque toujours être ré-implémenté avec des sauts normaux avec très peu de temps système).

  • Avoir deux méthodes dans une classe qui ne diffèrent que par le type de retour.

    La spécification du langage Java n'autorise pas deux méthodes de la même classe lorsqu'elles diffèrent _/seulement par leur type de retour (c'est-à-dire le même nom, la même liste d'arguments, ...). Cependant, la spécification JVM n’ayant aucune restriction de ce type, un fichier de classe can peut contenir deux méthodes de ce type. Il n’existe aucun moyen de produire un tel fichier de classe à l’aide du compilateur Java normal. Il y a un bel exemple/explication dans cette réponse .

60
Joachim Sauer

Voici quelques fonctionnalités pouvant être effectuées dans le bytecode Java mais pas dans le code source Java:

  • Lancement d'une exception vérifiée d'une méthode sans déclarer que la méthode le lève. Les exceptions cochées et non cochées sont vérifiées uniquement par le compilateur Java, pas par la JVM. Pour cette raison, Scala peut par exemple générer des exceptions vérifiées à partir de méthodes sans les déclarer. Cependant, avec les génériques Java, il existe une solution de contournement appelée sournoisement .

  • Avoir deux méthodes dans une classe dont le type de retour diffère uniquement, comme déjà mentionné dans Réponse de Joachim : La spécification du langage Java n'autorise pas deux méthodes dans la même classe lorsqu'elles diffèrent uniquement dans leur type de retour (même nom, même liste d'arguments, ...). Cependant, la spécification JVM n’ayant aucune restriction de ce type, un fichier de classe can contient deux méthodes de ce type. Il n’existe aucun moyen de produire un tel fichier de classe à l’aide du compilateur Java normal. Il y a un bel exemple/explication dans cette réponse .

12
Esko Luontola
  • GOTO peut être utilisé avec des étiquettes pour créer vos propres structures de contrôle (autres que forwhile etc.)
  • Vous pouvez remplacer la variable locale this à l'intérieur d'une méthode
  • En combinant ces deux éléments, vous pouvez créer un bytecode optimisé pour créer un appel final (je le fais dans JCompilo ).

En tant que point connexe, vous pouvez obtenir le nom du paramètre pour les méthodes s’il a été compilé avec debug ( Paranamer le fait en lisant le code intermédiaire

6

Peut-être que la section 7A de ce document présente un intérêt, bien qu’il s’agisse de bytecode pitfalls plutôt que de bytecode features.

4
eljenso

En langage Java, la première instruction d'un constructeur doit être un appel au constructeur de la super-classe. Le bytecode n'a pas cette limitation, mais la règle est que le constructeur de la super classe ou un autre constructeur de la même classe doit être appelé pour l'objet avant d'accéder aux membres. Cela devrait permettre plus de liberté telle que:

  • Créez une instance d'un autre objet, stockez-la dans une variable locale (ou pile) et transmettez-la en tant que paramètre au constructeur de la super classe tout en conservant la référence dans cette variable pour une utilisation ultérieure.
  • Appelez différents autres constructeurs en fonction d'une condition. Cela devrait être possible: Comment appeler un constructeur différent de manière conditionnelle en Java?

Je ne les ai pas testées, alors corrigez-moi si je me trompe.

3
msell

Une chose que vous pouvez faire avec du code octet, plutôt que du code Java simple, est de générer un code qui peut être chargé et exécuté sans compilateur. De nombreux systèmes utilisent JRE plutôt que JDK et si vous souhaitez générer du code de manière dynamique, il peut être préférable, voire plus facile, de générer du code octet au lieu du code Java avant de pouvoir l'utiliser.

2
Peter Lawrey

J'ai écrit un optimiseur de bytecode lorsque j'étais I-Play (il a été conçu pour réduire la taille du code pour les applications J2ME). Une fonctionnalité que j'ai ajoutée était la possibilité d'utiliser du bytecode inline (similaire au langage d'assemblage inline en C++). J'ai réussi à réduire la taille d'une fonction faisant partie d'une méthode de bibliothèque en utilisant l'instruction DUP, car j'ai besoin de la valeur deux fois. J'ai également eu des instructions de zéro octet (si vous appelez une méthode qui prend un caractère et que vous voulez passer un int, que vous savez qu'il n'est pas nécessaire de la lancer, j'ai ajouté int2char (var) pour remplacer char (var) et le supprimerait. l'instruction i2c pour réduire la taille du code.J'ai aussi fait faire float a = 2.3; float b = 3.4; float c = a + b; et qui serait converti en point fixe (plus rapide, et certains J2ME ne l'ont pas soutien virgule flottante).

1
nharding

En Java, si vous essayez de remplacer une méthode publique par une méthode protégée (ou toute autre réduction d'accès), vous obtenez une erreur: "tentative d'attribution de privilèges d'accès plus faibles". Si vous le faites avec le bytecode de la machine virtuelle Java, le vérificateur le convient bien et vous pouvez appeler ces méthodes via la classe parent comme si elles étaient publiques.

0
Joseph Sible