Attributs de classe Java (Champs)
Déclarez des champs d'instance sur une classe Java, définissez leurs valeurs initiales et accédez-y via des objets.
Les attributs d'une classe sont les variables déclarées à l'intérieur — les données que chaque objet porte. La plupart des auteurs les appellent champs (c'est le terme de la spécification du langage Java), et "attribut" est le terme POO plus général ; ils désignent la même chose. Ce chapitre traite de leur déclaration, des valeurs avec lesquelles ils démarrent, et de la façon de les lire et de les écrire depuis l'extérieur de la classe.
Déclarer un champ
Un champ ressemble à une variable locale, mais il se trouve dans le corps de la classe plutôt qu'à l'intérieur d'une méthode :
public class Book {
String title;
String author;
int pages;
boolean inPrint;
}Chaque instance de Book obtient sa propre copie de ces quatre champs. Deux livres ont deux chaînes title séparées, deux entiers pages séparés, et ainsi de suite. Ils vivent aussi longtemps que l'objet vit, c'est-à-dire jusqu'à ce qu'aucune référence ne pointe plus vers lui.
Valeurs par défaut
Si vous n'initialisez pas un champ, Java l'initialise pour vous. Les valeurs par défaut dépendent du type :
| Type | Valeur par défaut |
|---|---|
byte, short, int, long | 0 |
float, double | 0.0 |
char | '�' (le caractère nul, point de code 0 — pas un espace) |
boolean | false |
| tout type objet | null |
Book b = new Book();
System.out.println(b.title); // null
System.out.println(b.pages); // 0
System.out.println(b.inPrint); // falseC'est l'une des principales différences entre les champs et les variables locales à l'intérieur des méthodes — les variables locales n'ont pas de valeur par défaut, et le compilateur refuse de vous laisser en lire une avant de lui avoir assigné une valeur. Les champs commencent toujours avec quelque chose.
Initialiseurs inline
Vous pouvez donner une valeur à un champ là où vous le déclarez :
public class Book {
String title = "Untitled";
int pages = 0;
boolean inPrint = true;
}L'initialiseur s'exécute une fois par objet, lors de la création de cet objet. Il s'exécute dans l'ordre de déclaration, avant le corps du constructeur. Si un champ nécessite une configuration plus complexe, c'est le rôle du constructeur.
Lire et écrire des champs
Vous utilisez <référence>.<champ> depuis l'extérieur, et simplement <nomDuChamp> (ou this.<nomDuChamp>) depuis l'intérieur de la classe elle-même :
Book b = new Book();
b.title = "Effective Java"; // write
String t = b.title; // readÀ l'intérieur de la classe :
public class Book {
String title;
void rename(String t) {
title = t; // same as this.title = t;
}
}Le chapitre sur le mot-clé this explique quand vous avez besoin du qualificateur explicite this. et quand vous n'en avez pas besoin.
Conventions de nommage
Les noms de champs Java utilisent le lowerCamelCase :
String firstName; // good
String first_name; // not Java style
String FirstName; // looks like a classLes booléens sont souvent nommés avec les préfixes is ou has (isPublished, hasIndex), ce qui rend les sites d'appel naturellement lisibles : if (book.isPublished). Les constantes — les champs qui ne changent pas — sont écrites en UPPER_SNAKE_CASE et marquées static final, ce qui est couvert dans les chapitres static et final.
Champs d'instance vs champs de classe
Par défaut, les champs appartiennent à chaque instance — chaque objet a sa propre copie. En ajoutant static, le champ appartient à la classe elle-même ; il n'y a qu'une seule copie, partagée entre toutes les instances :
public class Counter {
int count; // instance — each Counter has its own
static int total; // class — one shared by all Counters
}
Counter a = new Counter();
Counter b = new Counter();
a.count++; b.count++; b.count++;
Counter.total++;
System.out.println(a.count); // 1
System.out.println(b.count); // 2
System.out.println(Counter.total); // 1, accessed through the classVous trouverez l'histoire complète dans le chapitre static ; pour l'instant, supposez que chaque champ est un champ d'instance, sauf s'il est explicitement marqué static.
Les champs publics sont généralement une erreur
Java vous permet d'écrire public String title; et de laisser le code extérieur l'atteindre et le modifier directement. En pratique, vous ne le faites presque jamais. Une fois qu'un champ est public, vous avez perdu la capacité de valider les écritures, de changer le type plus tard, ou d'envelopper les lectures avec de la logique — quiconque touche le champ est codé en dur dans sa représentation actuelle.
Le modèle standard consiste à marquer les champs private et à exposer des getters et setters à la place :
public class Book {
private String title;
public String getTitle() { return title; }
public void setTitle(String t) { this.title = t; }
}C'est l'encapsulation. Les chapitres sur l'encapsulation et les getters & setters couvrent le modèle complet. Nous montrons les champs directement dans les premiers exemples pour la clarté, mais le vrai code Java les garde privés.
Les champs contiennent des références, pas des objets
Lorsque le type d'un champ est une classe (et non un primitif), le champ est une référence. Deux objets peuvent partager le même objet sous-jacent via leurs champs :
public class Author { String name; }
public class Book { Author author; }
Author a = new Author();
a.name = "Joshua Bloch";
Book b1 = new Book(); b1.author = a;
Book b2 = new Book(); b2.author = a; // same Author object
a.name = "J. Bloch";
System.out.println(b1.author.name); // J. Bloch
System.out.println(b2.author.name); // J. BlochLes mêmes avertissements du chapitre précédent s'appliquent : c'est parfois ce que vous voulez, et parfois un bug. Si un Book doit avoir son propre Author, vous assigneriez new Author() à chacun.
Un exemple concret
Quelle est la suite ?
Les champs sont l'état d'un objet. L'autre moitié — son comportement — se trouve dans les méthodes déclarées sur la classe. Le prochain chapitre sur les méthodes de classe montre comment attacher des méthodes aux instances et comment elles accèdent aux champs que vous venez de définir.