Object, et en redescendant toute la hiérarchie jusqu'à la classe qu'elle charge, et pour toutes les classes nouvellement chargées :
Exemple 32. Exécution des blocs statiques lors du chargement d'une classe
public class Marin { // dans le fichier Marin.java
public static long dateDeChargement = System.currentTimeMillis() ; // 1
static {
System.out.println("Chargement de la classe Marin") ; // 2
}
}
public class Capitaine extends Marin { // dans le fichier Capitaine.java
public static long dateDeChargement = System.currentTimeMillis() ; // 3
static {
System.out.println("Chargement de la classe Capitaine") ; // 4
}
}
Capitaine déclenche les opérations statiques dans l'ordre de leur numérotation. À partir de la version 5 de Java ces blocs sont exécutés lors de la première instanciation de la classe
Capitaine.
Marin ci-dessous.
Exemple 33. Constructeur vide par défaut - 1
public class Marin {
private String nom ;
public String getNom() {
return this.nom ;
}
public void setNom(String nom) {
this.nom = nom ;
}
}
Marin marin = new Marin() ;Si l'on spécifie un constructeur dans cette classe, alors le constructeur vide par défaut n'est plus créé. Si l'on reprend notre exemple :
Exemple 34. Constructeur vide par défaut - 2
public class Marin {
private String nom ;
public Marin(String nom) {
this.nom ;
}
public String getNom() {
return this.nom ;
}
}
Marin marin = new Marin("Surcouf") ;
Considérons l'exemple suivant.
Exemple 35. Constructeur vide par défaut - 3
public class Marin { // dans le fichier Marin.java
private String nom ;
// constructeur vide de la classe Marin
public Marin() {
nom = "indéfini" ;
}
}
public class Capitaine extends Marin { // dans le fichier Capitaine.java
private String grade
public Capitaine(String grade) {
this.grade = grade ;
}
}
Capitaine :
Capitaine capitaine = new Capitaine("Capitaine de vaisseau") ;
L'instanciation de l'objet
capitaine déclenche les opérations suivantes :
Capitaine est appelé ;
Marin, qui initialise le champ
nom ;
Capitaine initialise le champ
grade.
Capitaine.
Il est également possible pour un constructeur d'appeler explicitement un unique constructeur. Cet appel ne peut être que la première instruction de ce constructeur. Voyons cela sur un exemple.
Exemple 36. Appels explicites de constructeurs
public class Marin { // dans le fichier Marin.java
private String nom ;
public Marin(String nom) {
this.nom = nom ;
}
}
public class Capitaine extends Marin { // dans le fichier Capitaine.java
private String grade
public Capitaine(String nom, String grade) {
super(nom) ; // appel du constructeur de la super classe
this.grade = grade ;
}
public Capitaine(String grade) {
this("indéfini", grade) ; // appel du constructeur de même classe
}
}
false ou
null suivant leur type ;
Exemple 37. Exemple d'une instanciation complexe
public class Marin { // dans le fichier Marin.java
private long dateCreation = System.currentTimeMillis() ;
{
// ceci est un bloc non statique
System.out.println(i) ;
}
private String nom ;
public Marin() {
this.nom = "indéfini" ;
}
public Marin(String nom) {
this.nom = nom ;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
}
public class Capitaine extends Marin { // dans le fichier Capitaine.java
private int grade ;
private long dateCreation = System.currentTimeMillis() ;
{
// ceci est un bloc non statique
System.out.println(i) ;
}
public Capitaine(String nom) {
super(nom) ;
}
public Capitaine(String nom, int grade) {
this(nom) ;
this.grade = grade ;
}
}
Capitaine m = new Capitaine("Surcouf", 2) ;
Les opérations s'enchaînent de la façon suivante :
(String, int) de
Capitaine ;
(String) de
Capitaine ;
(String) de
Marin ;
dateCreation de
Marin ;
Marin ;
(String) de
Marin ;
dateCreation de
Capitaine ;
Capitaine ;
(String) de
Capitaine ;
(String, int) de
Capitaine.
final.
finalize() dans la classe
Object,
détaillée ici, qui joue le rôle de callback avant que le
garbage collector
ne détruise un objet.
final, alors il n'est pas possible de l'étendre. De nombreuses classes sont
final dans l'API standard : c'est le cas de
String, et de toutes les classes enveloppes des classes de base.
Il peut être utilisé de façon analogue sur une méthode. Une méthode déclarée
final ne peut pas être surchargée par une méthode d'une classe qui étendrait la classe dans laquelle cette méthode est définie. Par exemple, les méthodes
wait() de la classe
Object sont finales, elles ne peuvent donc pas être surchargées.
Il peut être utilisé sur le champ d'une classe, statique ou non. Dans ce cas, une fois intialisé, ce champ ne pourra plus être modifié. Se pose alors la question, à quel moment peut-on, et doit-ont initialiser un champ
final ?
Un champ
static final, doit être initialisé par un initialiseur de champ ou un bloc statique.
Un champ
final (non statique) doit être initialisé par un initialiseur de champ, un bloc non statique, ou dans le constructeur.
Un champ
final, statique ou non, ne peut pas être initialisé deux fois, une fois initialisé, il n'est plus possible de changer sa valeur.
Si un objet possède plusieurs constructeurs, et qu'il possède un champ
final, alors l'initialisation de ce champ doit suivre le même processus, quel que soit le constructeur appelé. En particulier, si ce champ est initialisé dans un constructeur, alors tous les constructeurs doivent l'initialiser, y compris le constructeur par défaut.
Le mot-clé
final peut être posé sur un paramètre reçu par une méthode. Dans ce cas, ce paramètre ne pourra être modifié.
Enfin, le mot-clé
final peut être posé sur une variable définie dans une méthode. Dans ce cas, la valeur de cette variable ne pourra être modifiée.
Notons qu'une classe locale, anonyme ou non, peut accéder aux variables et paramètres définis dans la méthode dans laquelle elle-même a été définie, que si ceux-ci sont
final.
Les règles d'utilisation des champs
final sont complexes et subtiles. Heureusement les environnements de développement intégré sont là pour nous aider. Ils nous marquent les erreurs d'accès ou d'initialisation, et nous rappellent les règles à appliquer pour corriger nos erreurs.
String
StringBuffer et
StringBuilder