28/05/2010

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

Code :

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);
}
}


Réponse
Les lignes 5, 6, 7 et 8 sont illégales.

Explication
- la ligne 4 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.
- la ligne 5 elle est illégale, car 256 est un entier qui ne peut pas rentrer dans un byte (les bytes peuvent contenir des valeurs comprises entre -128 et 127). Nous ne sommes donc pas dans le cas particulier de la ligne 3, et le cast implicite n'est pas autorisé.
- la ligne 6 est illégale pour les mêmes raisons
- la ligne 8 est illégale pour les mêmes raisons que la ligne 4.
- la ligne 7 est illégale, car nous somme dans le cadre d'un passage de paramètre, et non pas d'une assignation, il ne s'agit donc pas du cas particulier de la ligne
3.


Point théorique associé
ici

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