L'héritage est un concept important en orientation objet. L'héritage est un autre moyen important d'améliorer la réutilisabilité du code en plus de la composition. Nous avons vu dans la composition que la composition est l'interface fonctionnelle d'un objet qui est appelé à plusieurs reprises. Comme nous le verrons, l'héritage permet de réutiliser des définitions de classes existantes.
Héritage de classe
Lorsque nous avons défini une classe auparavant, nous sommes partis de zéro et avons défini chaque membre de la classe en détail. Par exemple, la classe Human suivante :
Copiez le code comme suit :
classeHumain
{
/**
*accesseur
*/
public int getHeight()
{
renvoie this.height;
}
/**
* mutateur
*/
public void growHeight (int h)
{
ceci.hauteur = ceci.hauteur + h;
}
/**
*haleine
*/
souffle du vide public()
{
System.out.println("hu...hu...");
}
hauteur int privée ;
}
À partir de la définition de classe ci-dessus, nous pouvons comprendre tous les détails de la classe : les données membres de la classe, les méthodes de la classe et l'interface de la classe.
Nous devons maintenant définir une nouvelle classe, telle que la classe Woman, et supposer que la classe Woman est assez similaire à la classe Human :
Humain & Femme
Nous pouvons repartir de zéro et définir complètement la classe Woman comme avant :
Copiez le code comme suit :
Femme de classe
{
/**
*accesseur
*/
public int getHeight()
{
renvoie this.height;
}
/**
* mutateur
*/
public void growHeight (int h)
{
ceci.hauteur = ceci.hauteur + h;
}
/**
*haleine
*/
souffle du vide public()
{
System.out.println("hu...hu...");
}
/**
* nouvelle méthode
*/
public Humain giveBirth()
{
System.out.println("Accoucher");
retour (nouveau Humain (20));
}
hauteur int privée ;
}
Un programmeur aura beaucoup de mal à écrire le programme ci-dessus. De nombreuses définitions ont été écrites dans la classe Human, mais nous devons les retaper. La classe Woman ajoute uniquement une nouvelle méthode giveBirth() (cette méthode crée et renvoie un nouvel objet Human).
En utilisant l'héritage, nous pouvons éviter la duplication ci-dessus. Laissez la classe Woman hériter de la classe Human, et la classe Woman aura automatiquement les fonctions de tous les membres publics de la classe Human.
Nous utilisons le mot-clé extends pour indiquer l'héritage :
Copiez le code comme suit :
classe Femme étend Humain
{
/**
* nouvelle méthode
*/
public Humain giveBirth()
{
System.out.println("Accoucher");
retour (nouveau Humain (20));
}
}
De cette façon, nous économisons beaucoup de saisie. Grâce à l'héritage, nous créons une nouvelle classe, appelée classe dérivée. La classe héritée (Humain) est appelée la classe de base (classe de base). La classe dérivée utilise la classe de base comme base pour sa propre définition et complète la méthode giveBirth() qui n'est pas définie dans la classe de base. La relation d'héritage peut être exprimée comme suit :
Héritage : la flèche pointe vers la classe de base
Vous pouvez utiliser la classe Test suivante pour tester :
Copiez le code comme suit :
Test de classe publique
{
public static void main (String[] arguments)
{
Femme aWoman = new Woman();
aWoman.growHeight(120);
System.out.println(aWoman.getHeight());
}
}
Couche dérivée
Par héritage, nous créons la classe Woman. L'ensemble du processus peut être divisé en trois niveaux : définition de la classe de base, définition de la classe dérivée et utilisation externe.
Le niveau de définition de classe de base consiste à définir une classe normalement, comme la définition de classe humaine ci-dessus.
Du point de vue des utilisateurs externes (comme un objet de classe Woman créé dans la classe Test), la classe dérivée possède une interface externe unifiée :
Pour les utilisateurs externes, l’interface ci-dessus est suffisante. Du seul point de vue de l’interface, les classes dérivées n’ont rien de spécial.
Cependant, les programmeurs doivent être prudents lorsqu'ils travaillent au niveau des définitions de classes dérivées :
Premièrement, l’interface est mixte : les méthodes getHeight() et growHeight() proviennent de la classe de base, tandis que la méthode giveBirth() est définie à l’intérieur de la classe dérivée.
Il existe d’autres complications. Nous pouvions auparavant accéder librement aux membres de la classe au sein de la classe (en utilisant cela pour faire référence à l'objet). Cependant, lorsque nous sommes dans le périmètre de définition de la classe Femme, nous ne pouvons pas accéder aux membres privés de la classe de base Humain. Nous rappelons le sens de privé : les membres privés sont uniquement destinés à un usage interne de la classe. La classe Femme est une nouvelle classe différente de la classe Humain, elle est donc située en dehors de la classe Humain. Dans une classe dérivée, les membres privés de la classe de base ne sont pas accessibles.
Mais ce qui est intéressant, c’est que nos méthodes growHeight() et getHeight() fonctionnent toujours. Cela montre que les membres privés de la classe de base existent, nous ne pouvons tout simplement pas y accéder directement.
Afin de clarifier le concept, nous devons comprendre le mécanisme de génération des objets de classe dérivés. Lorsque nous créons un objet d'une classe dérivée, Java crée d'abord un objet de classe de base (sous-objet) et ajoute les autres membres définis par la classe dérivée qui constituent un objet de classe dérivée. Ce que les utilisateurs externes peuvent voir, ce sont les membres publics de la classe de base et des classes dérivées. Comme indiqué ci-dessous :
Objets de classe de base et objets de classe dérivés
La couleur jaune dans l'image est l'objet de classe de base. Les membres de la couche de base peuvent accéder les uns aux autres (utilisez ceci dans la définition de la classe Humaine pour faire référence à l'objet de la classe de base).
La partie bleue est le nouveau contenu de l'objet dérivé. J'appelle cette partie le calque dérivé. Les parties bleue et jaune forment ensemble l’objet dérivé. Les membres de la couche dérivée peuvent accéder les uns aux autres (ceci dans la définition de Femme). De plus, nous pouvons également accéder aux membres publics de la couche de base. Pour cette raison, nous utilisons le mot-clé super pour faire référence à l'objet de classe de base et utilisons super.member pour représenter les membres de base (publics).
Lorsque nous sommes dans la couche dérivée (c'est-à-dire lors de la définition de la classe Woman), nous ne pouvons pas accéder aux membres privés de base rouge. Lorsque nous sommes à l'extérieur, nous ne pouvons accéder ni aux membres privés de la couche dérivée violette ni aux membres privés de la couche de base rouge.
(Les membres privés de la couche dérivée ont des restrictions d'accès, ils sont donc marqués d'une barre oblique. Les membres privés de la couche de base ont le plus de restrictions d'accès, ils sont donc marqués d'une barre oblique)
Super est similaire à ceci et est également un paramètre implicite. Lorsque nous sommes à différents niveaux de définition de classe, cela aura des significations différentes. Soyez prudent avec les mots-clés this et super.
(Java n'oblige pas l'utilisation de this et super. Java peut identifier automatiquement la propriété des membres dans de nombreux cas. Mais je pense que c'est une bonne pratique.)
protégé
Nous avons précédemment introduit deux mots-clés liés aux autorisations d'accès, privé et public, qui contrôlent la visibilité externe des membres. Maintenant, nous introduisons un nouveau mot-clé d'accès : protected.
Les membres marqués protégés sont visibles dans cette classe et ses classes dérivées. Ce concept est facile à comprendre. Autrement dit, les membres protégés de la classe de base sont accessibles par la couche dérivée, mais ne sont pas accessibles par l'extérieur, comme indiqué ci-dessous :
remplacement de méthode
L'interface externe de l'objet de classe dérivé est finalement composée des membres publics de l'objet de classe de base et des membres publics de la couche dérivée. Si les membres publics de la classe de base et les membres publics de la couche dérivée ont le même nom, lequel est affiché dans l'interface Java ?
Nous avons déjà mentionné dans les constructeurs et la surcharge de méthodes que Java utilise à la fois le nom de la méthode et la liste des paramètres pour déterminer la méthode à appeler. Une méthode est déterminée par le nom de la méthode et la liste des paramètres. Dans le problème ci-dessus, si seuls les noms de méthodes sont les mêmes mais que les listes de paramètres sont différentes, alors les deux méthodes seront présentées à l'interface en même temps, ce qui ne nous posera aucun problème. Lors d'un appel externe, Java décidera quelle méthode utiliser (surcharge de méthode) en fonction des paramètres fournis.
Que se passe-t-il si le nom de la méthode et la liste des paramètres sont identiques ? Lors de la dérivation du calque, nous pouvons également utiliser super et ceci pour déterminer de quelle méthode il s'agit. En externe, nous ne présentons qu’une interface unifiée, nous ne pouvons donc pas proposer deux méthodes en même temps. Dans ce cas, Java restituera les méthodes de couche dérivées au lieu des méthodes de couche de base.
Ce mécanisme est appelé remplacement de méthode. Les remplacements de méthode peuvent être utilisés à bon escient pour modifier les méthodes des membres de la classe de base. Par exemple, dans la couche dérivée, c'est-à-dire lors de la définition de Woman, vous pouvez modifier la méthode Breath() fournie par la classe de base :
Copiez le code comme suit :
classe Femme étend Humain
{/**
* nouvelle méthode
*/
public Humain giveBirth()
{
System.out.println("Accoucher");
retour (nouveau Humain (20));
}
/**
* remplacer Human.breath()
*/
souffle du vide public()
{
super.souffle();
System.out.println("su...");
}
}
Notez que nous sommes actuellement dans la couche dérivée et que nous pouvons toujours appeler la méthode Breath() de l'objet de classe de base via super. Lorsque nous appelons la classe Woman en externe, en raison d'un remplacement de méthode, nous ne pouvons plus appeler la méthode de l'objet de classe de base.
Le remplacement de méthode conserve l’interface de l’objet de classe de base et utilise l’implémentation de la couche dérivée.
Constructeur
Après avoir compris les concepts d'objets de classe de base et de couches dérivées, les méthodes de construction des classes dérivées sont plus faciles à comprendre.
Nous devons définir un constructeur avec le même nom que la classe dans la définition de la classe dérivée. Dans ce constructeur :
1. Étant donné que l'objet de classe de base est créé et initialisé en premier lors de la création d'un objet dérivé, le constructeur de la classe de base doit être appelé en premier. Nous pouvons utiliser l'instruction super(argument list) pour appeler le constructeur de la classe de base.
2. Une fois l'objet de classe de base créé, commencez à créer la couche dérivée (initialisation des membres de la couche dérivée). C'est la même chose que la méthode de construction générale, se référer à la méthode de construction et à la méthode de surcharge
Par exemple, dans le programme suivant, la classe Human a un constructeur :
Copiez le code comme suit :
classeHumain
{
/**
* constructeur
*/
humain public (int h)
{
ceci.hauteur = h;
}
/**
*accesseur
*/
public int getHeight()
{
renvoie this.height;
}
/**
* mutateur
*/
public void growHeight (int h)
{
ceci.hauteur = ceci.hauteur + h;
}
/**
*haleine
*/
souffle du vide public()
{
System.out.println("hu...hu...");
}
hauteur int privée ;
}
La définition de la classe dérivée Classe Femme et sa méthode de construction :
Copiez le code comme suit :
classe Femme étend Humain
{
/**
* constructeur
*/
Femme publique (int h)
{
super(h); // constructeur de classe de base
System.out.println("Bonjour Pandora!");
}
/**
* nouvelle méthode
*/
public Humain giveBirth()
{
System.out.println("Accoucher");
retour (nouveau Humain (20));
}
/**
* remplacer Human.breath()
*/
souffle du vide public()
{
super.souffle();
System.out.println("su...");
}
}
Résumer
s'étend
remplacement de méthode
protégé
super.membre, super()