Classes et objets en Java
Définissez une classe Java et créez des objets (instances) à partir d'elle — la base du modèle orienté objet de Java.
Une classe est une définition ; un objet est une instance de cette définition existant à l'exécution. La classe décrit à quoi ressemble un chien et ce qu'il peut faire ; un objet est Rex, un chien spécifique vivant en mémoire pendant que votre programme s'exécute. Tout ce qui suit repose sur cette distinction.
Définir une classe
La définition d'une classe se trouve dans son propre fichier .java, nommé d'après la classe. Le corps contient des champs (les données que chaque instance porte) et des méthodes (le comportement que chaque instance peut effectuer).
public class Dog {
String name;
int age;
void describe() {
System.out.println(name + ", age " + age);
}
}Cela déclare un type. Cela ne crée pas encore de chiens — exactement comme écrire int ne crée pas d'entier.
Créer un objet avec new
Le mot-clé new demande à la JVM d'allouer de l'espace pour une instance et de renvoyer une référence vers celle-ci :
Dog d = new Dog();Trois choses se produisent sur cette ligne :
- Allocation. La JVM trouve de l'espace sur le tas suffisant pour un
Dog. - Initialisation par défaut. Chaque champ obtient une valeur par défaut —
nullpour les objets,0pour les entiers,falsepour les booléens. - Appel du constructeur. Le
()invoque un constructeur. Nous n'en avons pas écrit, donc Java fournit un constructeur sans argument par défaut qui ne fait rien de plus. Le prochain chapitre sur les constructeurs explique comment écrire le vôtre.
Après cela, d contient une référence — une petite valeur qui pointe vers l'objet sur le tas. L'objet lui-même est la chose plus grande sur le tas.
Lire et écrire des champs
On accède à un champ en écrivant <référence>.<champ> :
d.name = "Rex";
d.age = 3;
System.out.println(d.name); // RexL'accès aux champs permet également d'appeler des méthodes :
d.describe(); // Rex, age 3Le point est le même dans les deux cas ; que le côté droit soit un champ ou une méthode dépend simplement de ce qui suit.
Les références ne sont pas l'objet
C'est la phrase la plus importante de ce chapitre : une variable de type classe contient une référence, pas l'objet lui-même.
Dog a = new Dog();
a.name = "Rex";
Dog b = a; // copies the REFERENCE, not the dog
b.name = "Buddy";
System.out.println(a.name); // Buddya et b pointent vers le même objet sur le tas, donc le modifier via l'un est visible via l'autre. Comparons avec les primitives :
int x = 5;
int y = x; // copies the value
y = 9;
System.out.println(x); // still 5x et y sont indépendants — les primitives sont copiées par valeur. Le chapitre sur le passage par valeur approfondit ce que cela signifie pour les arguments de méthode.
null et NullPointerException
Une variable de référence peut être null, ce qui signifie « ne pointe vers aucun objet » :
Dog d = null;
d.describe(); // NullPointerExceptionnull est ce que vous obtenez si vous n'avez jamais assigné d'objet, ou si un champ de type objet n'a jamais été explicitement initialisé. Déréférencer null (écrire d.quelquechose quand d == null) lève une NullPointerException à l'exécution. Écrire du code qui ne plante pas sur null représente la moitié du Java pratique.
NullPointerException est une erreur d'exécution, pas une erreur de compilation — le code se compile correctement et échoue seulement lorsque cette ligne s'exécute réellement. La solution est de s'assurer que la variable pointe vers un vrai objet (d = new Dog();) ou de protéger avec une vérification (if (d != null) d.describe();) avant de la déréférencer.Comparer des objets : == vs equals
Pour les références, == demande « ces deux variables pointent-elles vers le même objet ? » :
Dog a = new Dog();
Dog b = new Dog();
Dog c = a;
System.out.println(a == b); // false — different objects
System.out.println(a == c); // true — same objectSi vous souhaitez comparer le contenu de deux objets, vous appelez plutôt une méthode equals — chaque classe hérite d'une méthode par défaut de Object, mais celle par défaut effectue simplement une égalité de référence. Vous surchargez equals pour lui donner le sens que vous souhaitez ; voir le chapitre equals & hashCode plus loin dans cette partie.
Un fichier, plusieurs objets
Une seule définition de classe supporte un nombre illimité d'instances. Elles partagent toutes la structure mais chacune a son propre état :
Dog rex = new Dog(); rex.name = "Rex"; rex.age = 3;
Dog molly = new Dog(); molly.name = "Molly"; molly.age = 7;
rex.describe(); // Rex, age 3
molly.describe(); // Molly, age 7Une méthode comme describe lit depuis this — l'objet sur lequel elle a été appelée — donc le même code affiche une sortie différente selon l'instance sur laquelle vous l'appelez.
Où vivent les classes
Un fichier .java qui déclare public class Dog doit être nommé Dog.java. Vous pouvez avoir des classes non publiques dans le même fichier, mais une seule classe public par fichier, et son nom doit correspondre au nom de fichier. Pour les petits programmes de ce chapitre, nous placerons souvent des classes auxiliaires dans le même fichier que main en utilisant des classes imbriquées static, juste pour garder l'exemple dans un seul fichier.
Un exemple complet
Et ensuite
Vous pouvez déclarer une classe et l'instancier, mais jusqu'ici le seul champ que vous avez écrit acceptait « n'importe quelle valeur ». Le prochain chapitre sur les attributs de classe aborde les champs correctement — déclaration, valeurs par défaut, portée d'instance vs de classe, et les conventions que le code Java suit.