Une idée pourquoi j'ai besoin de convertir un littéral entier en (int) ici?

122

Dans l'exemple suivant

int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles

Je ne peux pas lancer -128avec (Integer)mais je peux lancer (int) -128.

J'ai toujours pensé que -128c'était du inttype et le lancer avec (int)devrait être redondant.

L'erreur sur la ligne avec i3est

cannot find symbol variable Integer

J'ai essayé cela avec la mise à jour 29 de Java 6 et la mise à jour 1 de Java 7.

EDIT: Vous obtenez le même comportement avec +128au lieu de -128. Il semble y avoir confusion entre les opérateurs unaires et binaires.

Peter Lawrey
la source
5
quel est ton compilateur? Integer i = -128;cela devrait cependant compiler.
bestsss
bizarre, se Integer i3 = (Integer) (-128);conforme cependant.
Eng.Fouad
2
@ Eng.Fouad, Peter, les symboles unaires (+ -) ont une associativité de droite à gauche et plus, moins sont de gauche à droite. L'effet de -128 serait le même que +128 et mettre 0 devant devrait être corrigé, c'est-à-dire 0-128 ou 0 + 128. (Je ne peux pas tester atm mais je parie que ce sera le cas)
bestsss
Bonne question! Je voudrais personnellement voir une référence JLS pour la résolution des opérateurs unaires / binaires et quand un cast est traité comme une expression. Sinon, il est possible que d'autres compilateurs ne le considèrent pas comme une erreur!
Bringer128 du
1
Aussi FYI l'erreur que j'obtiens dans mon IDE est Expression expectedoù le Integerest.
Bringer128

Réponses:

151

Le compilateur essaie de soustraire 128de (Integer)au lieu de convertir -128en Integer. Ajouter ()pour le réparer

Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles

Selon BoltClock, dans les commentaires, le cast intfonctionne comme prévu, car il s'agit d'un mot réservé et ne peut donc pas être interprété comme un identifiant, ce qui a du sens pour moi.

Et Bringer128 a trouvé la référence JLS 15.16 .

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Comme vous pouvez le voir, la conversion en un type primitif en nécessite n'importe quel UnaryExpression, tandis que la conversion en un type de référence nécessite un UnaryExpressionNotPlusMinus. Celles-ci sont définies juste avant CastExpression à JLS 15.15 .

Jens Schauder
la source
31
Je pense que c'est parce que intc'est un mot-clé en Java, mais ce Integern'est pas le cas. Puisqu'il ints'agit d'un mot-clé, vous ne pouvez pas l'utiliser comme identifiant pour une variable ou une classe, laissant la seule possibilité qu'il soit un transtypage. Cela expliquerait cela.
BoltClock
@BoltClock a incorporé votre commentaire dans la réponse.
Jens Schauder
3
Pour rendre cette réponse encore plus stellaire, voulez-vous ajouter mon lien vers le JLS?
Bringer128
3
Une ride intéressante (pour moi) sur cette question est de savoir comment nous résolvons le problème analogue en C #, qui a également une ambiguïté dans la grammaire entre «expression entre parenthèses comme opérande en opérateur de soustraction binaire» et «opérateur de conversion où l'opérande droit de la cast est une expression moins unaire ". Voir la section 7.7.6 de la spécification C # pour une description détaillée de l'heuristique que nous utilisons pour essayer d'être intelligent dans la résolution de l'amgiguité.
Eric Lippert
1
@BillK Pourquoi dites-vous ça? La spécification C # ne fait pas référence à la surcharge d'opérateurs dans la section 7.7.6, donc ce n'était pas un problème pour eux.
Bringer128 du
48

J'ai trouvé la référence JLS. 15.16 .

 CastExpression:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Comme vous pouvez le voir, la conversion en un type primitif en nécessite n'importe quel UnaryExpression, tandis que la conversion en un type de référence nécessite un UnaryExpressionNotPlusMinus. Celles-ci sont définies juste avant CastExpression à JLS 15.15 .

Vous devez soit changer la distribution en un type primitif:

... (int) -128;

Ou vous pouvez changer l'expression à droite de la distribution en une expression unaire non plus moins:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or
Bringer128
la source
12

Le compilateur interprète le -comme l'opérateur moins à deux arguments, c'est-à-dire qu'il essaie de soustraire 128 à un autre nombre nommé Integer, mais il n'y a pas de telle variable dans la portée.

Cela compile:

Integer i3 = (Integer) (-128)
Barend
la source
Vous pouvez ajouter un commentaire sur pourquoi (int)fait une différence.
Peter Lawrey
1
C'est dû à l'auto-boxe, non?
Brian Roach
9

Cela peut être lié à l'analyse syntaxique. Remarquerez que

Integer i4 = (Integer) (-128); 

fonctionne très bien.

En général, vous ne devez pas convertir en classe Integer. Cela implique quelque chose appelé auto-boxing et peut provoquer des erreurs subtiles dans votre code. La méthode préférée pour faire ce que vous voulez est:

Integer i6 = Integer.valueOf(-128)
Krystian Cybulski
la source
1
cast to Integer est exactement du sucre synthétique pour valueOf.
bestsss du
4
oui, mais parfois le sucre synthétique échoue de manière subtile. J'ai eu du mal à détecter les exceptions de pointeur nul dans les grandes applications en raison de l'auto-boxing. Nous sommes allés jusqu'à traiter l'auto-boxing comme des erreurs pour éviter les maux de tête à l'avenir. La magie est agréable, mais quand elle échoue, la tête fait mal. Je trouve qu'il vaut mieux être explicite et éviter les maux de tête.
Krystian Cybulski
NPE sont b1tch w / outboxing, vrai. Cas d'espèce comme for (int i in Collection<Integer>)b / c le NPE est à un endroit absolument inattendu. En fait, je n'utilise pas Integer w / autoboxing car la plage de cache est petite (bien qu'elle puisse être augmentée avec l'option XX) mais j'ai une classe appelée IntegerProvider (depuis 1.1) pour faire la même chose. Utilisation de Map (any from java.util) Integer-> Anything est généralement un problème de performances à moins qu'il ne soit utilisé pour des cas triviaux et qu'il existe presque toujours une meilleure solution.
bestsss du
Casting int en Integer ne peut jamais provoquer d'erreurs, sauf peut-être un débordement de tas. L'inverse n'est cependant pas vrai.
Ingo
@MattBall, je ne comprends pas tout à fait, le sucre synthétique est largement utilisé: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 et la synthèse sonne mieux pour moi.
bestsss
9

Il analyse Integer <minus operator> 128et ne trouve pas la variable Integer. Vous devrez mettre -128entre parenthèses:

Integer i3 = (Integer) (-128);  // compiles
Bohème
la source
J'ai attribué +1 à toutes les autres réponses car elles sont toutes correctes aussi :)
Bohème
7
Integer i3 = (Integer) (-128);

Le problème est que le -compilateur le voit comme un opérateur.

Brian Roach
la source
6

La ligne 3 est interprétée comme si vous essayez de déduire 128 de l'expression entre parenthèses et l'expression entre parenthèses n'est pas une expression de type int (elle traite le «-» comme un opérateur «-»). Si vous modifiez l'expression en:

Integer i3 = (Integer) (-128);

alors le compilateur comprendra que «-» est le moins unaire qui indique un entier négatif.

Udi Cohen
la source
3

Le compilateur C # a le même comportement. Cela donne une meilleure idée de la raison pour laquelle la compilation échoue:

Pour convertir une valeur négative, vous devez mettre la valeur entre parenthèses

JefClaes
la source