Différences dans l’auto-unboxing entre Java 6 et Java 7

J’ai remarqué une différence dans le comportement de déballage automatique entre Java SE 6 et Java SE 7. Je me demande pourquoi, car je ne trouve aucune documentation sur les modifications de ce comportement entre ces deux versions.

Voici un exemple simple:

Object[] objs = new Object[2]; objs[0] = new Integer(5); int myInt = (int)objs[0]; 

Cela comstack bien avec javac de Java SE 7. Cependant, si je donne l’argument “-source 1.6” au compilateur, j’obtiens une erreur sur la dernière ligne:

 inconvertible types found : java.lang.Object required: int 

J’ai essayé de télécharger le Java SE 6 pour comstackr avec le compilateur natif version 6 (sans option -source). Il est d’accord et donne la même erreur que ci-dessus.

Alors qu’est-ce que ça donne? D’un peu plus d’expérimentation, il semble que le déballage de Java 6 ne peut que déballer des valeurs qui, clairement (au moment de la compilation), sont du type boîte. Par exemple, cela fonctionne dans les deux versions:

 Integer[] objs = new Integer[2]; objs[0] = new Integer(5); int myInt = (int)objs[0]; 

Donc, il semble qu’entre Java 6 et 7, la fonctionnalité de désencapsulation a été améliorée de manière à pouvoir convertir et décompresser les types d’object en une seule opération, sans savoir (au moment de la compilation) que la valeur est correcte. Cependant, la lecture de la spécification de langage Java ou des articles de blog écrits au moment où Java 7 est sorti, je ne vois aucun changement, alors je me demande quel est le changement et comment s’appelle cette “fonctionnalité” ?

Juste une curiosité: En raison du changement, il est possible de déclencher de “mauvais” unboxings:

 Object[] objs = new Float[2]; objs[0] = new Float(5); int myInt = (int)objs[0]; 

Cela comstack bien mais donne une exception ClassCastException à l’exécution.

Une référence à ce sujet?

Il semble que le langage de la section 5.5 Conversion de casting de Java 7 JLS ait été mis à jour par rapport à la même section du JLS Java 5/6 , probablement pour clarifier les conversions autorisées.

Java 7 JLS dit

Une expression d’un type de référence peut subir une conversion de conversion en un type primitif sans erreur, par conversion en unboxing.

Java 5/6:

Une valeur d’un type de référence peut être convertie en un type primitif par conversion unboxing (§5.1.8).

Le JLS Java 7 contient également une table (tableau 5.1) de conversions autorisées (cette table n’est pas incluse dans le JLS Java 5/6) des types de référence aux primitives. Cela répertorie explicitement les conversions d’Object en primitives en tant que conversion de référence restreinte avec unboxing.

La raison est expliquée dans cet email :

Bottom line: Si la spécification permet (Object) (int) il faut aussi permettre (int) (Object).

Tu as raison; pour le dire plus simplement:

 Object o = new Integer(1234); int x = (int) o; 

Cela fonctionne dans Java 7, mais donne une erreur de compilation dans Java 6 et ci-dessous. Étrangement, cette fonctionnalité n’est pas bien documentée; par exemple, ce n’est pas mentionné ici . C’est discutable si c’est une nouvelle fonctionnalité ou un correctif de bogue (ou un nouveau bogue?), Voir quelques informations et discussions connexes . Le consensus semble indiquer une ambiguïté dans la spécification originale, ce qui a conduit à une implémentation légèrement incorrecte / incohérente sur Java 5/6, qui a été corrigée en 7, car elle était essentielle pour l’implémentation de JSR 292 (langages à typage dynamic).

L’autoboxing Java a maintenant quelques pièges et sursockets. Par exemple

 Object obj = new Integer(1234); long x = (long)obj; 

comstackra, mais échouera (avec ClassCastException ) à l’exécution. Cela fonctionnera plutôt:

long x = (long)(int)obj;