31/05/2010

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

Code :

class Util{
public static boolean Print(String s){
System.out.print(s);
return true;
}
}
class Parent{
static int i = Classe.init ( );
}
class Classe extends Parent {
static int i = 4;
static int init() {
assert Util.Print ( "A" );
return i;
}
}
public class AClass {
public static void main(String[ ] args){
Classe c = new Classe( );
Util.Print ( "" +Parent.i);
}
}


Réponse
Le programme affiche "A0"

Explication
Lorsque les assertions sont désactivées, l'évaluation des expressions passées en parametres des assert n'a pas lieu
Cependant, lorsque l'on accède à un objet avant de l'avoir initialisé, il se comporte comme si les assertions étaient activées.
Ici :

- Classe( ) lançe l'initialisation de Classe.
- l'initialisation de Classe lançe l'initialisation de Parent
- l'initialisation de Parent appelle Classe.init();
- Classe.init(); est exécutée comme si les assertions étaient activées, et renvoie Classe.i;
- l'initialisation de Parent se termine
- l'initialisation de Classe met Classe.i = 4;


Le programme affiche donc toujours A0


Point théorique associé
ici

Questions pièges Java n°4

Question 4 :
Qu'affiche le code suivant si on l'exécute sans activer les assertions (à supposer que la fonction main soit effectivement exécutée) :

class Util{
public static boolean Print(String s){
System.out.print(s);
return true;
}
}
class Parent{
static int i = Classe.init ( );
}
class Classe extends Parent {
static int i = 4;
static int init() {
assert Util.Print ( "A" );
return i;
}
}
public class AClass {
public static void main(String[ ] args){
Classe c = new Classe( );
Util.Print ( "" +Parent.i);
}
}

28/05/2010

Point théorique Java : Boxing Unboxing

1) Principe
A chaque type de primitive numérique ou booleéne est associée un Wrapper.
Les Wrappers sont : Boolean, Byte, Short, Character, Integer, Long, Float et Double.
Tous à l'exception de Boolean dérivent de Number.

Lors d'une assignation, d'un passage de paramètre à une fonction, d'une opération ou d'un cast explicite, on peut utiliser une valeur primitive à la place de son Wrapper et réciproquement.
La conversion qui intervient à ce moment là est appellée boxing (primitive -> wrapper) ou unboxing (wrapper->primitive)
Exemples :
Integer I1 = 4;
Vector MonVector = new Vector(); MonVector.add(2.0);
int i2 = I1 +7;
if (i2 > I1) ;
Byte b = (byte)i2;

2) Ce que le boxing/unboxing ne fait pas
Le Boxing / Unboxing peut convertir une primitive en son wrapper associé et réciproquement.
Le Boxing ne peut pas convertir une primitive en un wrapper associé à une autre primitive.
Long l = 2; // ceci n'est pas légal
Le Unboxing ne peut pas convertir un wrapper en une primitive associée à un autre wrapper.
byte b = (Integer)2; // ceci n'est pas légal
Le Boxing/Unboxing ne se fait que quand on passe explicitement un Wrapper (respectivement une primitive), là où une primitive (resp un Wrapper) est attendu.
Double f = 2.0, g= 2.0; // ici (f == g) renverait false car les objets sont comparés directement sans être unboxés
Float h = 2.0f; // ici (f == h) provoquerait une erreur de compilation

3) Mutualisation
Au lançement de la jvm, celle-ci crée un certain nombre de Wrappers par défaut.
Ces wrappers sont automatiquement utilisés lors du boxing des valeurs auxquelles ils correspondent.
Ainsi, lorsque l'on écrit :
Byte b1 = 1;
Byte b2 = 1;
On a b1 == b2. C'est à dire que les deux références b1 et b2 désignent le même objet.
Les Wrappers par défaut sont :
- Tous les Byte
- Les Character compris entre 0 et 127
- Les Short, Integer et Long compris entre -128 et 127