J'ai noté une différence de comportement de déballage automatique entre Java SE 6 et Java SE 7. Je me demande pourquoi, car je ne trouve pas toute documentation des 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 compile très bien avec javac de Java SE 7. Cependant, si je donne au compilateur l'argument "-source 1.6" 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 compiler avec le compilateur natif de la version 6 (sans aucune option -source). Il accepte et donne la même erreur que ci-dessus.
Alors qu'est-ce qui donne? D'après certaines expérimentations, il semble que le déballage dans Java 6 ne peut déballer que les valeurs qui clairement (au moment de la compilation) sont du type encadré. Par exemple, cela fonctionne dans les deux versions:
Integer[] objs = new Integer[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];
Il semble donc qu'entre Java 6 et 7, la fonctionnalité de déballage ait été améliorée pour pouvoir couler et déballer les types d'objets d'un seul coup, sans savoir (au moment de la compilation) que la valeur est du type de boîte approprié. Cependant, en lisant la Java spécification de langue ou les articles de blog qui ont été écrits à l'époque Java 7 est sorti, je ne vois aucun changement de cette chose, donc 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" déballage:
Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];
Cela compile bien mais donne une ClassCastException à l'exécution.
Une référence à ce sujet?
Il ressemble au langage dans section 5.5 Conversion de conversion de Java 7 JLS a été mis à jour par rapport à la même section dans le Java 5/6 JLS , 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 transtypage en un type primitif sans erreur, par conversion d'unboxing.
Java 5/6:
Une valeur d'un type de référence peut être convertie en un type primitif par conversion d'unboxing (§5.1.8).
Le Java 7 JLS contient également un tableau (tableau 5.1) des conversions autorisées (ce tableau n'est pas inclus dans le Java 5/6 JLS) des types de référence) en primitives. Cette liste répertorie explicitement les transtypages d'Object en primitives en tant que conversion de référence restreinte avec unboxing.
La raison est expliquée dans cet email :
Conclusion: si la spécification. permet à (Object) (int), il doit également autoriser (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, elle n'est pas mentionnée ici . Il est discutable s'il s'agit d'une nouvelle fonctionnalité ou d'une correction de bogue (ou d'un nouveau bogue?), voir certains informations et discussion connexes . Le consensus semble pointer vers un - ambiguïté dans la spécification d'origine, 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 critique pour l'implémentation de JSR 292 (Langages à typage dynamique).
La boîte automatique Java a maintenant plus de pièges et de surprises. Par exemple
Object obj = new Integer(1234);
long x = (long)obj;
compilera, mais échouera (avec ClassCastException
) au moment de l'exécution. Cela fonctionnera plutôt:
long x = (long)(int)obj;