web-dev-qa-db-fra.com

Type primitif 'short' - conversion Java

J'ai une question sur le type primitif short en Java. J'utilise JDK 1.6.

Si j'ai ce qui suit:

short a = 2;
short b = 3;
short c = a + b;

le compilateur ne veut pas compiler - il dit qu'il "ne peut pas convertir d'int en court" et suggère que je fasse un transtypage en short, donc ceci:

short c = (short) (a + b);

fonctionne vraiment. Mais ma question est pourquoi ai-je besoin de lancer? Les valeurs de a et b sont comprises dans la plage short. La plage des valeurs courtes est {-32,768, 32767}. J'ai également besoin de lancer quand je veux effectuer les opérations -, *,/(je n'ai pas vérifié pour d'autres).

Si je fais la même chose pour le type primitif int, je n'ai pas besoin de transtyper aa + bb en int. Ce qui suit fonctionne bien:

int aa = 2;
int bb = 3;
int cc = aa +bb;

J'ai découvert cela en concevant une classe dans laquelle je devais ajouter deux variables de type short, et le compilateur voulait que je fasse un casting. Si je le fais avec deux variables de type int, je n'ai pas besoin de transtyper.

Une petite remarque: il en va de même avec le type primitif byte. Donc, cela fonctionne:

byte a = 2;
byte b = 3;
byte c = (byte) (a + b);

mais ce n'est pas:

byte a = 2;
byte b = 3;
byte c = a + b;

Pour long, float, double et int, il n'est pas nécessaire de procéder à un cast. Uniquement pour les valeurs short et byte.

75
user42155

Comme expliqué dans C # court (mais aussi pour les autres compilateurs de langage, comme Java)

Il existe une conversion implicite prédéfinie de court à int, long, float, double ou décimale.

Vous ne pouvez pas convertir implicitement des types numériques non littéraux de taille de stockage plus grande en short (voir la table des types d'intégraux pour connaître les tailles de stockage des types d'intégrale). Considérons, par exemple, les deux variables courtes suivantes x et y:

short x = 5, y = 12;

L'instruction d'affectation suivante génère une erreur de compilation , car l'expression arithmétique située à droite de l'opérateur d'affectation est évaluée par défaut en int.

short z = x + y;   // Error: no conversion from int to short

Pour résoudre ce problème, utilisez un cast:

short z = (short)(x + y);   // OK: explicit conversion

Il est toutefois possible d'utiliser les instructions suivantes, dans lesquelles la variable de destination a la même taille de stockage ou une taille de stockage supérieure:

int m = x + y;
long n = x + y;

Une bonne question de suivi est:

"pourquoi l'expression arithmétique à droite de l'opérateur d'affectation est évaluée par défaut à int"?

Une première réponse peut être trouvée dans:

Classification et vérification formelle du pliage constant entier

La spécification du langage Java définit exactement le mode de représentation des nombres entiers et l'évaluation des expressions arithmétiques entières . Ceci est une propriété importante de Java car ce langage de programmation a été conçu pour être utilisé dans des applications distribuées sur Internet. A Java programme est nécessaire pour produire le même résultat indépendamment de la machine cible qui l’exécute .

En revanche, C (et la plupart des langages de programmation impératifs et orientés objet largement utilisés) est plus bâclé et laisse de nombreuses caractéristiques importantes ouvertes. L'intention derrière cette spécification de langue inexacte est claire. Les mêmes programmes C sont supposés fonctionner sur une architecture 16 bits, 32 bits ou même 64 bits en instanciant l'arithmétique entière des programmes sources avec les opérations arithmétiques intégrées au processeur cible. Cela conduit à un code beaucoup plus efficace car il peut utiliser directement les opérations disponibles de la machine. Tant que les calculs d'entiers ne traitent que des nombres "suffisamment petits", il ne se produira aucune incohérence.

En ce sens, l'arithmétique des entiers C est un espace réservé qui n'est pas défini exactement par la spécification du langage de programmation, mais qui n'est instancié complètement que par la détermination de la machine cible.

Java définit précisément comment les entiers sont représentés et comment l'arithmétique des entiers doit être calculée.

      Java Integers
--------------------------
Signed         |  Unsigned
--------------------------
long  (64-bit) |
int   (32-bit) |
short (16-bit) |  char (16-bit)
byte  (8-bit)  |

Char est le seul type entier non signé. Ses valeurs représentent les caractères Unicode, à partir de \u0000 à \uffff, c'est-à-dire de 0 à 216−1.

Si un opérateur entier a un opérande de type long, l'autre opérande est également converti en type long. Sinon, l'opération est effectuée sur des opérandes de type int. Si nécessaire, des opérandes plus courts sont convertis en int . Les règles de conversion sont exactement spécifiées.

[Des notes électroniques en informatique théorique 82 n ° 2 (2003)
Blesner-Blech-COCV 2003: Sabine GLESNER , Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Karlsruhe, Allemagne]

60
VonC

EDIT: Ok, maintenant nous savons que c'est Java ...

La section 4.2.2 de la Java indique:

Le langage de programmation Java fournit un certain nombre d'opérateurs qui agissent sur des valeurs intégrales:

[...]

  • Les opérateurs numériques, qui donnent une valeur de type int ou long:
  • [...]
  • Les opérateurs additifs + et - (§15.18)

En d’autres termes, c’est comme C # - l’opérateur d’ajout (appliqué aux types intégraux) ne donne toujours que int ou long, raison pour laquelle vous avez besoin de la distribution pour attribuer à un short variable.

Réponse originale (C #)

En C # (vous n'avez pas spécifié le langage, donc je suppose), les seuls opérateurs d'addition sur les types primitifs sont:

int operator +(int x, int y);
uint operator +(uint x, uint y);
long operator +(long x, long y);
ulong operator +(ulong x, ulong y);
float operator +(float x, float y);
double operator +(double x, double y);

Celles-ci figurent dans la spécification C # 3.0, section 7.7.4. De plus, l'addition décimale est définie:

decimal operator +(decimal x, decimal y);

(L'addition d'énumération, la concaténation de chaînes et la combinaison de délégués y sont également définies.)

Comme vous pouvez le constater, il n'y a pas d'opérateur short operator +(short x, short y) - les deux opérandes sont donc implicitement convertis en int, et le formulaire int est utilisé. Cela signifie que le résultat est une expression de type "int", d'où la nécessité de transtyper.

17
Jon Skeet

En C # et Java, l'expression arithmatique à droite de l'affectation est évaluée à int par défaut. C'est pourquoi vous devez utiliser une forme abrégée, car il n'existe pas de formulaire de conversion implicite, même pour des raisons évidentes.

16
Rik

Etant donné qu'on n'a pas répondu à la question "Pourquoi int par défaut" ...

Premièrement, "défaut" n'est pas vraiment le terme correct (bien que suffisamment proche). Comme l'a noté VonC, une expression composée d'ints et de long aura un long résultat. Et une opération composée d'ints/logs et de doubles aura un double résultat. Le compilateur promeut les termes d'une expression dans n'importe quel type offrant une plage et/ou une précision plus grande dans le résultat (les types à virgule flottante sont supposés avoir une plage et une précision plus grandes que l'intégrale, bien que vous perdiez en précision la conversion des grands longs en double).

Une mise en garde est que cette promotion se produit uniquement pour les termes qui en ont besoin. Ainsi, dans l'exemple suivant, la sous-expression 5/4 n'utilise que des valeurs intégrales et est exécutée à l'aide de calculs entiers, même si l'expression globale implique un double. Le résultat n'est pas ce que vous pourriez attendre ...

(5/4) * 1000.0

OK, alors pourquoi les octets et short sont-ils promus en int? Sans aucune référence pour me sauvegarder, c'est pour des raisons pratiques: il existe un nombre limité de bytecodes.

"Bytecode", comme son nom l'indique, utilise un seul octet pour spécifier une opération. Par exemple iadd , qui ajoute deux ints. Actuellement, 205 codes d'opération sont définis , et le calcul d'un entier prend 18 pour chaque type (c'est-à-dire 36 au total entre entier et long), sans compter les opérateurs de conversion.

Si court et octet chacun a son propre jeu de codes opération, vous seriez à 241, limitant la capacité de la JVM à se développer. Comme je l'ai dit, aucune référence ne vient me soutenir, mais je suppose que Gosling et al ont dit "à quelle fréquence les gens utilisent-ils des shorts?" D'autre part, la promotion d'octet à int conduit à cet effet pas si merveilleux (la réponse attendue est 96, la réalité est -16):

byte x = (byte)0xC0;
System.out.println(x >> 2);
7
kdgregory

Quelle langue utilisez-vous?

Beaucoup de langages basés sur C ont pour règle que toute expression mathématique est exécutée avec une taille égale ou supérieure. De ce fait, une fois que vous avez ajouté deux courts métrages, le résultat est de type int. Cela provoque le besoin d'un casting.

5
Darron

Java utilise toujours au moins 32 bits pour les calculs. Ceci est dû à l'architecture 32 bits qui était courante en 1995 lorsque Java a été introduit. La taille du registre dans la CPU était de 32 bits et l'unité logique arithmétique acceptait 2 nombres de la longueur d'un processeur. Les processeurs ont donc été optimisés pour de telles valeurs.

C'est la raison pour laquelle tous les types de données prenant en charge les opérations arithmétiques et ayant moins de 32 bits sont convertis en int (32 bits) dès que vous les utilisez pour des calculs.

En résumé, cela était principalement dû à des problèmes de performances et est conservé de nos jours pour des raisons de compatibilité.

2
Andreas Mennel

En Java, chaque expression numérique comme:

anyPrimitive zas = 1;
anyPrimitive bar = 3;
?? x = zas  + bar 

x aura toujours pour résultat d'être au moins un entier, ou un long si l'un des éléments d'addition était long.

Mais il y a des bizarreries difficiles

byte a = 1; // 1 is an int, but it won't compile if you use a variable
a += 2; // the shortcut works even when 2 is an int
a++; // the post and pre increment operator work
1
Jaime Hablutzel

AFAIS, personne ne parle de final usage pour cela. Si vous modifiez votre dernier exemple et définissez les variables a et b comme final variables, le compilateur est assuré que leur somme, valeur 5, peut être affectée à une variable de type byte, sans perte de précision. Dans ce cas, il est bon que le compilateur affecte la somme de a et b à c. Voici le code modifié:

final byte a = 2;
final byte b = 3;
byte c = a + b;
1
snr

Tout type de données inférieur à "int" (sauf Boolean) est converti implicitement en "int".

Dans ton cas:

short a = 2;
short b = 3;
short c = a + b;

Le résultat de (a + b) est implicitement converti en un entier. Et maintenant, vous l'assignez à "court" .Alors vous obtenez l'erreur.

bref, octet, caractère - pour tout cela, nous aurons la même erreur.

1
Rushikesh Garadade

J'aimerais ajouter quelque chose qui n'a pas été signalé. Java ne prend pas en compte les valeurs que vous avez données aux variables (2 et 3) dans ...

court a = 2; court b = 3; court c = a + b;

Donc, autant que Java le sait, vous pourriez le faire ...

court a = 32767; court b = 32767; court c = a + b;

Ce qui serait en dehors de la plage de court, il fait automatiquement une liste des résultats, car il est "possible" que le résultat soit plus qu'un court mais pas plus qu'un entier. Int a été choisi comme "valeur par défaut" car, fondamentalement, la plupart des gens ne coderont pas en dur, mais des valeurs supérieures à 2 147 483 647 ou inférieures à -2 147 483 648.

0
Ross