28/05/2010

Questions pièges Java n°2

Question 2 :

Dans le programme suivant, quelles sont les lignes qui provoquent des erreurs de compilation :

public class AClass {
public static void method(byte b){}
public static void main(String[] args) {
byte b1 = 2;
byte b2 = 256;
char c = 10-20;
method(2);
method(256);
}
}

Point théorique Java : Conversions de primitives numériques


1) Règle générale

Les conversions élargissantes sont autorisées, qu'elles soient implicites ou explicites :
byte -> short -> int -> long -> float -> double
char -> int /

ex: int i = 4;
long l = i;
float f = (float)i;

Les conversions rétrécissantes explicites sont autorisées :
ex: int i = 4;
byte b = (byte)i;

contrex : char c = i; // illégal

2) Elargissant ne signifie pas qu'il n'y a pas de perte de précision
Il faut remarquer que si la conversion de toute valeur entière en valeur à virgule flottante est considérée comme une conversion élargissante, cela ne signifie pas pour autant qu'elle se fait sans perte de précision.
ex : System.out.println( ((int)(float)1234567890) - 1234567890); // ceci affiche 46

3) Cast de valeur flottante en valeur entière
Tout cast de double ou float en byte, short, ou char se fait en 2 étapes :
- cast de double ou float en int
- cast de int en byte short ou char

Ceci peut induire des effets de bord :
double D = 0x80000000p0;
long L = 0x80000000L;
System.out.println((short)D); // cette ligne affiche -1, car (int)D vaut 0x7FFFFFFF
System.out.println((short)L); // cette ligne affiche 0, car (int)L vaut -0x80000000

Rappel : Le cast d'un float ou un double supérieur à la plus grande valeur que peut contenir un int (0x7FFFFFFF) donne cette valeur.

4) Exceptions

Les conversion rétrécissante implicite sont autorisées quand les conditions suivantes sont remplies simultanément:
- il s'agit d'une assignation à une variable de type byte, short ou char ;
- les valeurs assignées sont des valeurs littérales ou finales ou des opérations de valeurs littérales ou finales;
- les valeurs assignées sont dans la fourchette d'existance de la variable à assigner (cela implique entre autre qu'elles sont entières et non à virgule)

Il s'agit d'un cas particulier fait pour faciliter le codage :
ex : byte b1 = 2; // ceci devrait être illégal car "2" est un entier, mais c'est légal
ex : short s = 2+2; // même chose
contrex : byte b2 = 128; // ceci est illégal car un byte ne peut contenir le nombre 128
contrex : char c = 5-6; // ceci est illégal car un byte ne peut contenir le nombre -1

Questions pièges Java n°1 : réponse

Code :

  public class AClass {
public static void main(String[] args) {
byte b = 2;
char c = -1;
short s = -3;
int i = c;
double d = 2.0;
float f = 2.0;
}
}


Réponse :
Les lignes 4 et 8 provoquent des erreurs de compilation.

Explication :
- la ligne 3 devrait être illégale car l'expression "2" est un entier et ne devrait pas pouvoir être assigné à un byte sans cast explicite. Cependant nous sommes dans un des seuls cas particuliers où cette règle ne s'applique pas, à savoir la conversion rétrécissante implicite.

- la ligne 4 elle est illégale, car -1 est un entier qui ne peut pas rentrer dans un char (il est négatif et les char sont non-signés). Nous ne sommes donc pas dans le cas particulier de la ligne 3, et le cast implicite n'est pas autorisé.

- la ligne 5 est légale pour les mêmes raisons que la ligne 3.

- la ligne 6 est légale : il s'agit d'un cast élargissant implicite.

- la ligne 7 est légale : il s'agit de l'assignation d'un double à une variable de type double : il n'y a pas de cast

- la ligne 8 est illégale, car l'espression "2.0" est un double et qu'elle ne peut pas être assignée à une variable de type float sans cast explicite. L'exception des lignes 3 et 5 ne s'applique qu'aux valeurs entières.


Point théorique associé :
ici