12/09/2010

Point théorique Java : Initialisations de variables

1) champs finaux.
Les champs finaux non-statiques d'une classe doivent être initialisés :
- soit lors de leur déclaration
- soit dans tous les constructeurs
- soit dans un bloc initialiseur

Les champs finaux statiques d'une classe doivent être initialisés :
- soit lors de leur déclaration
- soit dans un bloc initialiseur

2) Exceptions
Les initialisations des champs finaux non-statiques d'une classe ne sont pas autorisés à lancer des exceptions, sauf si celles-ci sont déclarées dans tous les constructeurs.
Les initialisations des champs finaux statiques d'une classe ne sont pas autorisés à lancer des exceptions. Pas du tout.

3) Utilisation de champs non-déclarés
3.1) principe
- Lors de l'initialisation d'un champ non-statique d'une classe, il est interdit de faire référence à des champs non-statiques non-finaux non-encore déclarés via leurs noms simples, sauf à gauche d'un opérateur d'assignation simple.
cette phrase peut s'écrire :
- Lors de l'initialisation d'un champ non-statique d'une classe, il est presque toujours interdit de faire référence à des champs non-statiques.
les cas où cela est autorisé sont détaillés ci-après.
Ainsi le code suivant n'est pas légal :

class R{
float f3 = f1;
float f1 = 4;
}


- De la même façon : lors de l'initialisation d'un champ statique d'une classe, il est interdit de faire référence à des champs statiques non-finaux non-encore déclarés via leurs noms simples, sauf à gauche d'un opérateur d'assignation simple.
Ainsi le code suivant n'est pas non plus légal :
class R{
static {f1++;};
static float f1 = 4;
}



- Ces règles s'appliquent aussi aux blocs d'initialisation.
Ainsi le code suivant n'est pas non plus légal :
class R{
{f1++;};
float f1 = 4;
}


3.2) utilisation de champs statiques pour initialiser des champs non-statiques
Il est parfaitement légal d'utiliser des champs statiques non-encore déclarés pour initialiser des champs non-statiques.
class R{
float f3 = f1; // ici f3 vaut bien 4
static float f1 = 4;
}


3.3) "nom simple"
L'utilisation d'un champ via un nom non-simple est autorisée. Ce code, par exemple, est autorisé :
class R{
float f3 = this.f1;
float f4 = getF1(); // à supposer que getF1 renvoie f1;
float f1 = 4;

static double d3 = R.d1;
static double d1 = 4;
}

Attention, le fait que cette utilisation soit autorisée n'implique pas que les initialisations se font dans un ordre hiérarchique.
Dans le code précédent, f3, f4 et d3 valent 0

3.4) champs finaux
L'utilisation de champs finaux non-encore déclarés pour l'initialisation de champs est légale.
Qui plus est, les champs finaux sont initialisés avant les autres.
Ainsi le code suivant est autorisé :
class R{
float f3 = f1; // ici f3 vaut 4
final float f1 = 4;
}


3.5) utilisation à gauche d'un opérateur d'assignation simple
Vocabulaire : l'opérateur d'assignation simple est l'opérateur = (par opposition aux opérateurs d'assignation composés : += *= %= >>= ...)
Cette utilisation est acceptée. Le code suivant, par exemple est légal :
class R{
float f3 = f1 = 4;
float f1 = 5;
}

Point théorique Java : Construction

1) Ordre

- 1. 	La première action du constructeur est d'initialiser ses paramètres
- 2. + Soit le constructeur n'est pas celui de Object, auquel cas il appelle un autre constructeur via :
* l'utilisation explicite de this(...)
* l'utilisation explicite de super(...)
* l'utilisation implicite de super() sans argument
+ Soit le constructeur est celui de Object et il passe à l'étape 3.
Cet appel implique le lançement des étapes 1 à 4 pour le constructeur appelé.
- 3. il exécute ensuite les instance initializers
- 4. puis le reste de son code


2) Surcharge
En java la surcharge des méthodes est valide dès le début de la création de l'objet.
Notament,le constructeur d'un objet peu appeler des méthodes surchargées, ce qui peut induire l'utilisation de variables non-initialisées.

09/09/2010

Questions pièges Java n°6b : réponse

Code :

class Base {
Base ( ) {init ( ); }
void init ( ) { System.out.println(2); }
}
class Derived extends Base{
int i = 4;
final int j = 4;
void init() { System.out.println ( i +" "+j); }
}
public class AClass {
public static void main(String[ ] args){
Derived c = new Derived( );
}
}


Réponse
0 4

Explication
En java la surcharge est effective, même dans le constructeur :
- Derived( ) appelle Base ( ) 
- Base appalle Derived.init( )
- init affiche i et j
- Derived( ) passe i à 4


La variable i n'est donc pas encore initialisée lors de la première exécution de init(), visiblement la valeur d'une variable non-initialisée pour ma version de la JVM est 0.

La variable j est, elle, curieusement initialisée, ce qui semble prouver que les instance initializer des variables finales ne sont pas traités de la même façon que ceux des variables non-finales.

Point théorique associé
ici et ici