Java 06 : Programmation Orientée Objet
Tu dois probablement te demander ce que l'on entend par objet dans le cadre d'un langage de programmation.
Un objet, c'est un concept (réel ou virtuel), qui possède des états et des comportements.
Cela peut, par exemple, être un canard ou une voiture :
- un canard aura comme états son âge, son sexe, son nombre de plumes... Et comme comportements le fait de nager, faire coin-coin, dormir...
- une voiture aura comme états sa marque, sa plaque d'immatriculation, son kilométrage... Et comme comportements le fait de rouler, de freiner, de klaxonner...
Tu vas donc découvrir comment créer et utiliser des objets en Java !
Objectifs
- Connaître les notions liées à la programmation orientée objet
- Apprendre les termes associés à chaque notion
- Savoir créer ses propres objets
- Savoir accéder aux états d'un objet et les modifier
- Savoir ajouter et exécuter des comportements sur un objet
Classe et attributs
1. Classe
Java est un langage de programmation orienté objet (POO) : tout objet y est représenté par une classe.
Prenons l'exemple d'un canard : sa classe, pour le moment vide, se présentera de la façon suivante :
public class Duck {
}
2. Attribut
Un objet est défini par ses états : en Java, on appelle cela des attributs.
Un attribut se présente sous la forme suivante :
private type nomAttribut;
Si tu reprends l'exemple du canard, voici quelques états possibles :
public class Duck {
private String name;
private int age;
private boolean swimming;
}
Pour le moment, ne prête pas trop attention à la visibilité
private.Tu verras pourquoi tu dois l'utiliser plus tard dans la quête.
Constructeur, instance et référence
1. Constructeur vide
Pour construire un objet, il va te falloir ajouter un constructeur. C'est lui qui va initialiser ton objet.
Un constructeur porte le même nom que ta classe, et est défini de la manière suivante :
public ClassName() {
}
Il est possible, comme dans cet exemple, de créer un constructeur vide. Cependant, si aucun constructeur n'est défini dans ta classe, cette dernière possédera un constructeur vide par défaut.
Forcément, avec un constructeur vide, aucun attribut n'aura de valeur à l'initialisation de l'objet.
2. Constructeur explicite
Dans le cas de la classe Duck, il serait intéressant d'initialiser le nom et l'âge du canard au moment même où l'on crée un nouvel objet.
Il t'est donc possible d'appeler explicitement un constructeur qui va initialiser les attributs d'un objet.
Tu peux cumuler plusieurs constructeurs et ainsi initialiser des attributs différents lors de la création d'un objet.
public class Duck {
private String name;
private int age;
private boolean swimming;
public Duck(String name) {
this.name = name;
this.age = 0;
this.swimming = false;
}
public Duck(String name, int age) {
this.name = name;
this.age = age;
this.swimming = false;
}
}
Le mot-clef
thispermet de cibler un attribut ou une méthode de l'objet de la classe en cours.Dans l'exemple précédent,this.ageappellera donc l'attributagede l'objet de la classeDuck.Cela permet de faire la différence entre l'argumentageet l'attributthis.age, qui auraient le même nom.
3. Instance
Quand on initialise un objet d'une classe, on dit que l'on fait une nouvelle instance d'une classe.
Par exemple, tu pourras dire que tu veux créer une nouvelle instance de la classe
Duck.
La notion de "nouvelle instance" se traduit par l'utilisation du mot-clef new. La création de l'instance se fait par l'appel d'un constructeur.
Lorsque tu crées une instance d'une classe, une case en mémoire va être allouée, et les attributs renseignés dans le constructeur prendront les valeurs correspondantes :
new Duck("Riri");

new Duck("Donald", 84);

4. Référence
Pour accéder à l'instance en mémoire, il faut un lien vers cette dernière : on appelle cela une référence.
En Java, cela revient à assigner l'instance à une variable, qui sera du type de la classe de l'objet :
Duck donald = new Duck("Donald", 84);

Ici donald est la référence d'une instance de la classe Duck.
Comme une instance est un espace en mémoire, il est possible d'avoir plusieurs références qui pointent vers une même instance :
Duck mysterMask = new Duck("Myster Mask");
Duck albertColvert = mysterMask;

Ici, mysterMask et albertColvert seront deux références vers une même instance. En clair, si l'un des deux est modifié, l'autre sera impacté !
Accesseurs et mutateurs
1. Accesseurs
Après la création de l'instance d'un objet, il peut être utile de récupérer la valeur d'un de ces attributs.
Créons un nouveau canard nommé "Fifi" en utilisant le constructeur Duck(String name, int age), avec son attribut age initialisé à la valeur 8.
Duck fifi = new Duck("Fifi", 8);

Si tu veux récupérer la valeur de son attribut age, il va falloir que tu accèdes à son attribut.
Tu serais tenté de le récupérer de la façon suivante :
Duck fifi = new Duck("Fifi", 8);
int age = fifi.age; // error: age has private access in Duck
Par convention, il faut donner la visibilité private aux attributs. Il est impossible de les modifier en dehors de la classe !
Une classe, c'est un peu comme une personne. Si tu veux récupérer son nom, tu vas le lui demander, tu ne vas pas fouiller son cerveau pour y trouver l'information !
Il est de la responsabilité d'une classe de partager et de mettre à jour l'état de ses attributs.
Il faut donc créer des accesseurs pour chaque attribut dont la classe autorisera l'accès. Un accesseur, appelé getter en anglais, se présente de la façon suivante :
public typeAttribut getAttribut() {
return this.attribut;
}
Dans ton cas, il devient possible de récupérer l'âge en ajoutant l'accesseur suivant :
public int getAge() {
return this.age;
}
Il faut ensuite appeler le getter de la façon suivante :
Duck fifi = new Duck("Fifi", 8);
int age = fifi.getAge(); // 8

Cas particulier de nommage des accesseurs : les booléens.
Dans le cas d'un attribut de type booléen, il ne faut pas nommer l'accesseur getAttribut mais isAttribut :
public boolean isSwimming() {
return this.swimming;
}
2. Mutateurs
De la même manière, si tu souhaites modifier un attribut, tu ne pourras pas le faire de la manière suivante :
Duck fifi = new Duck("Fifi", 8);
fifi.age = 9; // error: age has private access in Duck
Tu vas devoir définir des mutateurs, setters en anglais, qui se présentent de la façon suivante :
public void setAttribut(typeAttribut attribut) {
this.attribut = attribut;
}
Tu remarques l'utilisation du type
voidpour le retour de la méthode. En effet, le mutateur modifie bien l'état de l'attribut, mais il ne retourne aucun résultat !
Dans ton cas, pour modifier l'attribut age :
public void setAge(int age) {
this.age = age;
}
Il devient alors possible de modifier cet attribut :
Duck fifi = new Duck("Fifi", 8);
fifi.setAge(9); // 9;

Méthodes
Ton objet contient des états et des moyens d'accéder et de modifier ces derniers. Cependant, un objet peut aussi posséder des comportements. En Java, on appelle cela des méthodes.
1. Méthode d'instance
Une méthode va te permettre de faire des traitements et d'en renvoyer le résultat. Une méthode va s'exécuter sur l'instance d'une classe, et son résultat sera différent selon l'objet sur lequel elle sera exécutée.
Tu sais déjà écrire des méthodes et tu as eu l'occasion de les revoir avec les accesseurs et mutateurs. Cependant, un exemple supplémentaire ne te fera pas de mal :
public String nameAndAge() {
return "My name is " + this.getName() + " and I'm " + String.valueOf(this.getAge());
}
L'appel d'une méthode se fait sur l'instance de l'objet, soit :
Duck loulou = new Duck("Loulou", 8);
loulou.nameAndAge(); // My name is Loulou and I'm 8
2. Méthode statique
Tu as déjà eu l'occasion d'utiliser une méthode main(), tu as donc pu remarquer le mot clef static. Il te permet de signifier que la méthode doit être appelée directement sur une classe, et non sur l'instance d'une classe.
Une méthode statique ne te permet donc pas de récupérer l'état de ton objet. En clair, il te sera impossible d'afficher ou de modifier les attributs de la classe avec une méthode statique.
public static String quack() {
return "Quack!";
}
Et tu appelles la méthode sur la classe :
Duck.quack(); // Quack!
Une méthode statique est utile dans le cas où un comportement est le même pour tous les objets d'une classe.
Récapitulatif
Cela te fait un paquet de notions à aborder. Tu vas pouvoir les tester en récupérant le dépôt git donné en ressource.
Il contient deux classes : Duck, telle qu'elle t'a été présentée dans cette quête, et Pond, que tu compileras et exécuteras, afin de voir en détail :
-
la création d'une instance de classe
-
la création d'une référence à cette instance
-
la récupération d'un attribut avec un accesseur
-
la modification de l'état d'un attribut avec un mutateur
-
l'appel d'une méthode sur une instance de la classe
-
l'appel d'une méthode statique sur la classe
-
deux références sur une même instance, et l'impact de la modification de cette dernière
Ensuite, ouvre ces deux classes pour regarder comment tout ça est organisé. N'hésite pas à les modifier afin d'ajouter de nouveaux attributs, constructeurs, getters, setters et méthodes !
Challenge
Recensement à la Wild Code School !
Tu vas créer une classe pour représenter de façon la plus fidèle possible tes camarades !
- Crée une classe
Wilder - Ajoute les attributs
String firstnameetboolean aware - Crée un constructeur permettant d'initialiser
firstnameetaware - Ajoute des getters et setters pour tous les attributs, en respectant les conventions
- Ajoute une méthode
whoAmI()retournant le texte "Je m'appelle firstname et je suis aware" ou "Je m'appelle firstname et je ne suis pas aware", en fonction de l'état des attributsfirstnameetaware - Crée une classe
Classroomavec une méthode main() - Ajoute des références vers plusieurs instances de la classe
Wilderdans la méthode main() deClassroom - Pour chacune des références, affiche le retour de la méthode
whoAmI()dans le terminal - Compile et teste
Classroom: quand tout fonctionne, crée un dépôt git et envoie le tout sur GitHub - Partage le lien du dépôt GitHub en solution
Exemple de résultat attendu lors de l'exécution de Classroom :
$ Je m'appelle Jean-Claude et je suis aware
$ Je m'appelle Henri et je ne suis pas aware
Critères de validation
- Le dépôt GitHub contient bien les fichiers
Wilder.javaetClassroom.java - La classe
Wilderrespecte les conventions de la POO : attributs privés, utilisation du mot-clef this, getters et setters nommés correctement. - Des références à des instances de la classe
Wildersont présentes dans la classeClassroom - La classe
Classroomse compile sans erreur et affiche le résultat attendu dans le terminal