Casting Java: le compilateur est-il erroné, ou la spécification du langage est-elle erronée, ou ai-je tort?

StackOverflow https://stackoverflow.com/questions/5385743

  •  28-10-2019
  •  | 
  •  

Question

J'ai lu la spécification du langage Java, 3e édition, et j'ai trouvé ce que je pense être une différence entre la spécification et l'implémentation du compilateur javac. Les mêmes écarts existent dans le compilateur Eclipse.

La section 15.16 parle des expressions de cast . Cela dit qu'il devrait s'agir d'une erreur de compilation si le type d'argument ne peut pas être converti en type de diffusion via la conversion de conversion (section 5.5):

C'est une erreur à la compilation si le type à la compilation de l'opérande ne peut jamais être converti au type spécifié par l'opérateur de conversion selon les règles de conversion de conversion (§5.5). Sinon, au moment de l'exécution, la valeur de l'opérande est convertie (si nécessaire) en transtypant la conversion vers le type spécifié par l'opérateur de conversion.

La section 5.5 parle de conversion de diffusion . Il donne une liste des types de conversion autorisés. Spécifiquement absente de la liste est "la conversion de déballage suivie d'une conversion primitive élargie / rétrécie". Cependant cette séquence exacte de conversions semble être autorisée par le compilateur javac (et aussi par le compilateur Eclipse). Par exemple:

long l = (long) Integer.valueOf(45);

... compile très bien. (Le cast problématique est le cast en long; l'argument est de type java.lang.Integer, donc la conversion nécessite unboxing en int suivi d'une conversion primitive élargie).

De même, selon le JLS, il ne devrait pas être possible de convertir de byte en char, car cela (selon 5.1.4 ) nécessite une conversion primitive élargie et une conversion primitive rétrécie - cependant, cette conversion est également autorisée par le compilateurs.

Quelqu'un peut-il m'éclairer?

Modifier: depuis que j'ai posé cette question, j'ai déposé une rapport de bogue avec Oracle. Leur réponse est qu'il s'agit d'un "pépin dans le JLS".

Était-ce utile?

La solution

Je pense que vous avez raison, les compilateurs ont raison et la spécification est fausse ....

Ceci compile: (Object)45 et ce n'est pas le cas: (Long)45

La seule façon de donner un sens au comportement des compilateurs (y compris Intellij que j'utilise) est de modifier la conversion de diffusion pour être en accord avec la conversion d'attribution et la conversion d'invocation de méthode:

  • une conversion de boxe (§5.1.7) éventuellement suivi d'un élargissement conversion de référence

  • une conversion de déballage (§5.1.8) éventuellement suivi d'un élargissement conversion primitive.

plus

  • élargissement et rétrécissement de la convesion primitive

La spécification disait que "les conversions de diffusion sont plus inclusives que les conversions par appel d'attribution ou de méthode: une diffusion peut effectuer toute conversion autorisée autre qu'une conversion de chaîne ou une conversion de capture"

Autres conseils

D'après ma lecture, la conversion de int en long est autorisée par cette clause:

Une valeur d'un type primitif peut être convertie en un autre type primitif par conversion d'identité, si les types sont identiques, ou par une conversion primitive élargie ou une conversion primitive rétrécie.

La conversion de int en long est une conversion primitive élargie .

Cela laisse simplement la conversion de Integer en int, qui est prise en charge par la dernière puce:

une conversion de déballage

Bien sûr, le cast en long n'est même pas nécessaire dans l'exemple.

Considérez les quatre définitions suivantes:

final Integer io = Integer.valueOf(45);
final int i = io;
final long l1 = (long)i;
final long l2 = i;

Pensez-vous que l'un d'entre eux est surprenant?Votre exemple original n'a pas l'air différent;il élide simplement les variables intermédiaires.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top