Créer des Objets en Java

Nos programmes ne pourraient rien faire d’utile si nous n’avions pas la capacité de créer de nouveaux objets Java. Rappelez-vous qu’un objet est une instance d’une classe. Dans les sections suivantes, nous examinerons les constructeurs, les champs d’objets, les initialiseurs d’instance et l’ordre dans lequel les valeurs sont initialisées.

Appel des Constructeurs en Java

Pour créer une instance d’une classe, il suffit d’écrire new avant le nom de la classe et d’ajouter des parenthèses après. Voici un exemple :

Parc p = new Parc();

D’abord, vous déclarez le type que vous allez créer (Parc) et donnez un nom à la variable (p). Cela donne à Java un endroit pour stocker une référence à l’objet. Ensuite, vous écrivez new Parc() pour créer réellement l’objet.

Parc() ressemble à une méthode puisqu’il est suivi de parenthèses. C’est ce qu’on appelle un constructeur, qui est un type spécial de méthode qui crée un nouvel objet. Voici comment définir votre propre constructeur en Java:

public class Poussin {
    public Poussin() {
        System.out.println("dans le constructeur");
    }
}

Il y a deux points clés à noter concernant le constructeur : le nom du constructeur correspond au nom de la classe, et il n’y a pas de type de retour. Vous pourriez voir une méthode comme celle-ci :

public class Poussin {
    public void Poussin() { } // PAS UN CONSTRUCTEUR
}

Lorsque vous voyez un nom de méthode commençant par une majuscule et ayant un type de retour, faites-y attention. Ce n’est pas un constructeur puisqu’il y a un type de retour. C’est une méthode régulière qui compile mais ne sera pas appelée lorsque vous écrivez new Poussin().

Le but d’un constructeur est d’initialiser les champs, bien que vous puissiez y mettre n’importe quel code. Une autre façon d’initialiser les champs est de le faire directement sur la ligne où ils sont déclarés. Cet exemple montre les deux approches :

public class Poulet {
    int nombreOeufs = 12; // initialisation sur la ligne
    String nom;
    
    public Poulet() {
        nom = "Duc"; // initialisation dans le constructeur
    }
}

Pour la plupart des classes, vous n’avez pas besoin de coder un constructeur – le compilateur fournira un constructeur “ne fait rien” par défaut.

Lecture et Écriture des Champs Membres

Il est possible de lire et d’écrire des variables d’instance directement depuis l’appelant. Dans cet exemple, un cygne mère pond des œufs :

public class Cygne {
    int nombreOeufs; // variable d'instance
    
    public static void main(String[] args) {
        Cygne mere = new Cygne();
        mere.nombreOeufs = 1; // définir la variable
        System.out.println(mere.nombreOeufs); // lire la variable
    }
}

L’”appelant” dans ce cas est la méthode main(), qui pourrait être dans la même classe ou dans une autre classe. Cette classe définit nombreOeufs à 1 puis lit nombreOeufs directement pour l’afficher.

Vous pouvez même lire les valeurs des champs déjà initialisés sur une ligne initialisant un nouveau champ :

public class Nom {
    String prenom = "Theodore";
    String nomFamille = "Orignal";
    String nomComplet = prenom + nomFamille;
}

Les lignes avec prenom et nomFamille écrivent dans des champs. La ligne avec nomComplet lit et écrit des données. Elle lit les champs prenom et nomFamille, puis écrit le champ nomComplet.

Exécution des Blocs d’Initialisation d’Instance

Lorsque vous avez appris les méthodes, vous avez vu des accolades ({}). Le code entre les accolades (parfois appelé “à l’intérieur des accolades”) est appelé un bloc de code. Partout où vous voyez des accolades se trouve un bloc de code.

Parfois, les blocs de code sont à l’intérieur d’une méthode. Ceux-ci sont exécutés lorsque la méthode est appelée. D’autres fois, les blocs de code apparaissent en dehors d’une méthode. Ceux-ci sont appelés initialiseurs d’instance.

Combien de blocs voyez-vous dans l’exemple suivant ? Combien d’initialiseurs d’instance voyez-vous ?

public class Oiseau {
    public static void main(String[] args) {
        { System.out.println("Plumes"); }
    }
    { System.out.println("Neigeux"); }
}

Il y a quatre blocs de code dans cet exemple : une définition de classe, une déclaration de méthode, un bloc interne et un initialiseur d’instance. Compter les blocs de code est facile : il suffit de compter le nombre de paires d’accolades. S’il n’y a pas le même nombre d’accolades ouvrantes ({) et fermantes (}) ou si elles ne sont pas définies dans le bon ordre, le code ne compile pas.

Lorsque vous comptez les initialiseurs d’instance, gardez à l’esprit qu’ils ne peuvent pas exister à l’intérieur d’une méthode. La ligne avec “Neigeux” est un initialiseur d’instance, avec ses accolades en dehors d’une méthode. En revanche, la ligne avec “Plumes” n’est pas un initialiseur d’instance, car elle n’est appelée que lorsque la méthode main() est exécutée.

Suivre l’Ordre d’Initialisation

Lorsque vous écrivez du code qui initialise des champs à plusieurs endroits, vous devez garder une trace de l’ordre d’initialisation. C’est simplement l’ordre dans lequel différentes méthodes, constructeurs ou blocs sont appelés lorsqu’une instance de la classe est créée. En attendant, vous devez vous rappeler :

  • Les champs et les blocs d’initialisation d’instance sont exécutés dans l’ordre dans lequel ils apparaissent dans le fichier.
  • Le constructeur s’exécute après que tous les champs et blocs d’initialisation d’instance ont été exécutés.

Regardons un exemple :

public class Poussin {
    private String nom = "Duveteux";
    { System.out.println("définition du champ"); }
    
    public Poussin() {
        nom = "Petit";
        System.out.println("définition du constructeur");
    }
    
    public static void main(String[] args) {
        Poussin poussin = new Poussin();
        System.out.println(poussin.nom);
    }
}

L’exécution de cet exemple affiche :

définition du champ
définition du constructeur
Petit

Examinons ce qui se passe ici. Nous commençons par la méthode main() car c’est là que Java commence l’exécution. Nous appelons le constructeur de Poussin. Java crée un nouvel objet. D’abord, il initialise nom à “Duveteux”. Ensuite, il exécute l’instruction println dans l’initialiseur d’instance. Une fois que tous les champs et initialiseurs d’instance ont été exécutés, Java revient au constructeur. La ligne avec nom = "Petit" change la valeur de nom, et la ligne suivante affiche une autre instruction. À ce stade, le constructeur est terminé, puis l’exécution revient à l’instruction println dans le main().

L’ordre est important pour les champs et les blocs de code. Vous ne pouvez pas faire référence à une variable avant qu’elle ne soit définie :

{ System.out.println(nom); } // NE COMPILE PAS
private String nom = "Duveteux";

Que pensez-vous que ce code affiche ?

public class Oeuf {
    public Oeuf() {
        nombre = 5;
    }
    
    public static void main(String[] args) {
        Oeuf oeuf = new Oeuf();
        System.out.println(oeuf.nombre);
    }
    
    private int nombre = 3;
    { nombre = 4; }
}

Si vous avez répondu 5, vous avez raison. Les champs et les blocs sont exécutés en premier dans l’ordre, définissant nombre à 3 puis à 4. Ensuite, le constructeur s’exécute, définissant nombre à 5.

Voilà, vous savez tout sur les constructeurs Java !