Comprendre le mécanisme
La surcharge est résolue à partir des signatures et types connus à la compilation. Une méthode d’instance redéfinie est choisie selon l’objet réel à l’exécution. Les champs et méthodes static ne suivent pas ce même dispatch polymorphe. Un record fournit des composants, accesseurs et méthodes de valeur ; il n’effectue pas une copie profonde des objets reçus. Une hiérarchie sealed restreint ses sous-types directs autorisés.
Raisonner et vérifier
Protégez un objet de valeur contre les collections mutables reçues au constructeur. Les interfaces peuvent porter des méthodes default, mais un conflit doit être résolu explicitement. Un enum exprime un ensemble de cas ; une annotation comme Override fait vérifier une intention par le compilateur. La finalité d’un champ empêche sa réaffectation, sans bloquer les mutations internes de l’objet référencé.
Surcharge et redéfinition répondent à deux questions
Une surcharge propose plusieurs signatures ; la sélection dépend notamment des types connus à la compilation. Une redéfinition fournit une autre implémentation dans une hiérarchie compatible. Commencez par identifier quelle méthode est sélectionnable, puis examinez le receveur réel pour le dispatch d’instance. Deux méthodes partageant un nom ne suffisent pas à conclure qu’un appel sera décidé dynamiquement de la même manière.
Understand this common mistake
Toute méthode de même nom est une redéfinition.
Les signatures et la hiérarchie déterminent le mécanisme.
Le receveur réel choisit l’implémentation d’instance
Une variable de type parent peut référencer un objet enfant. Lorsqu’une méthode d’instance est correctement redéfinie, l’appel utilise l’implémentation correspondant à l’objet réel. Cette propriété permet une substitution utile pour des stratégies ou transports. Ne la généralisez pas sans distinction à tous les membres et mécanismes du langage : la sélection d’une surcharge et l’accès à certains membres suivent d’autres règles.
Understand this common mistake
Le type statique choisit toujours seul toute implémentation dynamique.
Le dispatch d’instance utilise le receveur réel.
Records et copie défensive
Un record fournit un modèle de composants et des comportements associés à sa valeur. Une référence de composant finale ne fige pas automatiquement les éléments d’une collection mutable. Si une liste reçue doit rester stable, une copie défensive du conteneur peut empêcher une modification extérieure de sa structure. Examinez encore les objets de cette liste : une copie superficielle ne crée pas leur immutabilité profonde.
Understand this common mistake
Un record rend tout graphe référencé profondément immuable.
Les composants peuvent référencer des objets mutables.
Borner les extensions avec sealed
Une hiérarchie sealed rend explicites des extensions permises selon les règles du langage. Ce choix facilite un raisonnement sur les variantes connues et certaines analyses exhaustives. Il ne remplace pas les invariants des constructeurs ni une politique d’accès métier. Lorsqu’un nouveau cas est introduit, recherchez les consommateurs qui supposaient la liste précédente et vérifiez les branches de traitement et les règles de compatibilité.
Understand this common mistake
sealed autorise n’importe quelle sous-classe sans contrainte.
Les extensions admises sont contrôlées.
Contrat d’interface et capacités limitées
Une interface décrit les opérations qu’un client peut demander à une implémentation. Cela aide à remplacer un service par un double de test sans coupler le consommateur à toutes les possibilités du service réel. L’interface ne donne pas un droit utilisateur sur les données. Dans une revue, identifiez les méthodes nécessaires puis vérifiez séparément les permissions appliquées à l’intérieur du parcours métier.
Understand this common mistake
Une interface accorde automatiquement une permission métier.
Le contrat de code ne décide pas des droits d’un acteur.
Final stabilise une extension, pas toute la sécurité
Une méthode final ne peut pas être redéfinie selon les règles du langage. Cela peut stabiliser une séquence choisie par la conception, mais ne prouve pas que le corps vérifie correctement les droits ou gère la concurrence. Écrivez les garanties attendues de cette séquence et testez-les. Le mot-clé ne doit pas devenir une justification qui remplace l’observation du comportement.
Understand this common mistake
final donne un pouvoir d’administration à la méthode.
Le mot-clé concerne le langage, pas l’accès métier.
Établir les invariants dès la construction
Le constructeur doit refuser ou représenter explicitement les états incomplets. Si un objet exige une quantité positive et une devise, une construction sans ces données oblige les méthodes à deviner l’intention. Pensez aussi aux références reçues : une collection mutable conservée directement peut être modifiée plus tard par son propriétaire initial. Une copie ou une abstraction de valeur doit suivre le besoin réel de stabilité.
Understand this common mistake
Un nom de classe suffit à garantir tout état métier.
Le code doit vérifier les conditions du domaine.
Encapsulation et frontière de code
La visibilité limite les accès permis entre éléments de code. private ne chiffre pas le contenu d’un champ et ne remplace pas une autorisation sur un compte métier. Un accesseur public peut aussi exposer indirectement un objet mutable qui contourne une intention d’encapsulation. Examinez ce qui est retourné et qui peut ensuite le modifier, pas seulement le mot-clé placé sur le champ.
Understand this common mistake
private chiffre automatiquement les champs.
Le contrôle de visibilité n’est pas un chiffrement.
Deux références peuvent désigner le même état
Affecter une référence d’objet ne duplique pas récursivement l’objet et ses dépendances. Une mutation à travers une variable peut donc être visible depuis l’autre. Pour une donnée dont le destinataire doit disposer indépendamment, définissez une stratégie de copie ou d’immuabilité. Testez un objet imbriqué : une copie du conteneur peut laisser ses éléments partagés et conserver exactement le couplage que vous vouliez éviter.
Understand this common mistake
Affecter un objet duplique récursivement toutes ses dépendances.
Deux variables peuvent référencer le même objet.
Égalité cohérente et collections de hachage
equals et hashCode doivent respecter un contrat cohérent pour les usages de hachage : deux objets égaux doivent produire le même hashCode. Un champ mutable participant à ces calculs peut rendre une clé difficile à retrouver après insertion dans une Map. Identifiez les composants stables de l’identité avant de choisir les champs. Le fait qu’une classe compile n’établit pas que sa notion de valeur convient au domaine.
Understand this common mistake
Deux objets égaux doivent pouvoir avoir des hashCode différents sans contrat.
Les collections de hachage exigent cette cohérence.
Atelier guidé : lire, expliquer et vérifier le code
class Parent { String label() { return "parent"; } }
class Child extends Parent { @Override String label() { return "child"; } }
class Main {
public static void main(String[] args) {
Parent value = new Child();
System.out.print(value.label());
}
} La variable value annonce le type Parent, mais l’objet construit est un Child. label est une méthode d’instance redéfinie, et le dispatch utilise donc l’implémentation enfant. Le texte affiché est child. Il faut distinguer cette décision de la sélection d’une surcharge, qui ne serait pas justifiée par le seul type réel du receveur.
Ajoutez un second objet Parent pour comparer les deux appels dans le même programme. Puis remplacez le résultat textuel par un collaborateur qui enregistre les appels afin d’en faire un test de substitution. Si une implémentation enfant exige des préconditions supplémentaires qui cassent le consommateur, le polymorphisme syntaxique ne suffira pas à rendre le contrat métier correct.
Spring : proxy transactionnel et auto-appel
@Service
public class CheckoutService {
public void checkout() { this.persist(); }
@Transactional
public void persist() { /* écritures SQL */ }
} Dans le mode proxy standard, l’interception transactionnelle s’applique aux appels qui traversent le proxy. Lorsque checkout appelle directement persist sur le même objet, cet auto-appel ne passe pas par cette frontière. L’annotation de persist ne crée donc pas une transaction pour ce chemin dans l’hypothèse où aucune transaction n’est déjà ouverte.
Placez l’annotation sur la frontière publique appelée via le proxy si elle correspond à l’unité métier, ou extrayez le travail transactionnel dans un autre bean injecté et appelé normalement. Ne déduisez pas une transaction du seul emplacement visuel de l’annotation.
Un test d’intégration doit invoquer le bean géré par Spring depuis l’extérieur, observer le comportement transactionnel et vérifier un rollback attendu. Instancier la classe avec new contourne aussi les mécanismes du conteneur. Les modes de weaving ou une transaction préexistante changeraient le contexte ; ils ne font pas partie du cas posé et doivent être annoncés lorsqu’ils sont utilisés.
Points de vigilance : Un appel interne au même objet ne traverse pas le proxy transactionnel. L’auto-appel contourne l’interception. Annoter la frontière appelée via le proxy ou extraire un autre bean est une solution. L’annotation ignorée ne crée pas de transactions par instruction ; l’autocommit relève de la connexion. final ne corrige pas le contournement du proxy et peut empêcher certaines interceptions.
Reference documentation ↗Worked example
record Batch(java.util.List<String> ids) {
Batch { ids = java.util.List.copyOf(ids); }
}
var input = new java.util.ArrayList<String>();
input.add("R1");
var batch = new Batch(input);
input.clear();
System.out.println(batch.ids().size());La copie non modifiable protège ici la liste contre un clear sur la collection initiale ; le résultat reste 1. Des éléments eux-mêmes mutables nécessiteraient un raisonnement supplémentaire.
Practical exercise
Créez une interface Reservation et deux implémentations ; appelez la même méthode via une référence d’interface.
View a suggested solution
Définissez le contrat, redéfinissez une méthode d’instance et vérifiez le dispatch. Ajoutez un record qui copie défensivement ses collections. Testez la mutation du conteneur d’origine.
Verification checklist
- Distinguer surcharge et redéfinition.
- Inspecter les références mutables des records.
- Utiliser Override pour vérifier l’intention.
Knowledge check
Related lesson: Objets, héritage, records et interfaces ↗Module validation
101 questions, local practice target of 75%. Suggested duration of 150 minutes, with no enforced deadline. Questions and choices are shuffled; corrections appear after submission. The quick lesson check and the final course exam remain separate exercises.
Start or resume the 101 questions →This records your own progress and does not certify mastery. Complete the exercise before moving on.
