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.

23/06/2010

Point théorique Java : Enchainements de conversion

Les enchainements de conversions autorisés lors d'une assignation, d'un passage de paramètre ou d'une opération sont :
graph.png
Légende :
// I = identity
// WP = Widening primitive
// WR = Widening reference
// B = Boxing
// U = Unboxing




Ainsi on peut écrire :

Number n = 4;		//(Boxing en Integer -> Widening reference)
Objet o = 4; //(id)
long l = (Integer)4; //(Unboxing -> de Widening primitive)


De la même facon
// même chose pour un passage de paramètre
MethodQuiAttendUnObject(4);
// même chose pour une opération
long l = ((Integer)4 + 7);


Mais on ne peut toujours pas écrire :
Long l = 4;	//(widening reference -> Boxing) est interdit


En pratique ces exemples semblent être les seuls cas intéressants.

(*) Identity est la conversion qui transforme un type en lui même.
Le fait que ce soit autorisé permet parfois de rendre le code plus lisible ex :
{
int quelquechose = 4;
... un grand nombre de lignes de code sans utiliser la variable quelquechose;
(int)quelquechose += 5;
}