Comment le polymorphisme Java est-il implémenté ?
Le polymorphisme en Java est le même qu'en C et est implémenté via une liaison tardive ou une liaison d'exécution. Lorsqu'une méthode référencée par un objet est appelée, le compilateur ne sait pas si la référence pointe vers l'objet type spécifié lors de la déclaration de la variable, ou vers un objet d'une sous-classe du type. Par conséquent, le compilateur ne peut pas se lier à une méthode spécifique pour cet appel. Il ne peut être lié à une méthode spécifique au moment de l'exécution que via l'identification de type d'exécution (RTTI) en Java. Voici un exemple spécifique :
class shape { public void draw() { print("shape"); } } class triangle extends shape { public void draw() { print("triangle"); } } public class Polymorphism { public static void main(String[] args) { shape s=new triangle(); s.draw(); }
Le résultat est que triangle
s est une référence de forme, mais au moment de l'exécution, car il s'agit d'un objet triangle, la méthode draw de triangle est toujours appelée.
Quelques pièges dans le polymorphisme Java
Remplacer les méthodes privées ?
Les méthodes privées ne peuvent pas être remplacées en Java. C'est en fait facile à comprendre, car les méthodes privées ne sont pas visibles dans les sous-classes. Les sous-classes n'héritent pas des méthodes privées de la classe parent, et encore moins les remplacent. Par conséquent, la méthode du même nom dans la sous-classe est une méthode complètement nouvelle.
public class Polymorphism { private void show() { print("show parent"); } public static void main(String[] args) { Polymorphism p=new privateMethod(); p.show(); } } class privateMethod extends Polymorphism { public void show() { print("show derived"); } }
Le résultat est un polymorphisme des champs show parent
et des méthodes statiques ?
Une sous-classe peut hériter des champs non privés de la classe parent. Les champs de la sous-classe sont-ils également polymorphes ? Jetons un coup d'œil à un exemple pratique :
class shape { protected int perimeter=1; public void draw() { print("shape"); } public int getPerimeter() { return perimeter; } } class triangle extends shape { int perimeter=3; public void draw() { print("triangle"); } public int getPerimeter() { return perimeter; } public int getSuperPerimeter() { return super.perimeter; } } public class Polymorphism { public static void main(String[] args) { shape s=new triangle(); print("s.perimeter:"+s.perimeter); print("s.getperimeter:"+s.getPerimeter()); triangle t=new triangle(); print("t.perimeter:"+t.perimeter); print("t.getperimeter:"+t.getPerimeter()); print("t.getsuperperimeter:"+t.getSuperPerimeter()); } }
Le résultat de cette opération contient les informations suivantes :
1 Une fois l'objet triangle converti en forme, l'accès direct aux champs est déterminé par le. compilateur, donc ce n'est pas le cas. Il affichera le polymorphisme et renverra 1.
2. Une fois l'objet triangle transformé en forme, la méthode pour accéder au champ est appelée. La méthode getperimeter du triangle est appelée en fonction de la liaison de retard du type d'objet d'exécution, et la valeur renvoyée est 3.
3. .t L'objet contient deux périmètres, l'un vient de lui-même et l'autre de sa classe parent. Dans le même temps, lorsque le champ est appelé avec le nom du champ, son propre champ de périmètre est renvoyé par défaut. Pour appeler le champ hérité de la classe parent, utilisez la méthode super.perimeter.
Ce résultat semble un peu déroutant. Afin d'éviter cette situation, nous déclarons généralement les champs comme privés (les sous-classes ne peuvent pas hériter). En même temps, il est préférable de ne pas déclarer les champs dans les sous-classes du même nom. hérité de la classe parent.
Les méthodes statiques n'ont pas de polymorphisme, car les méthodes statiques sont liées aux classes et il n'est pas nécessaire de connaître le type spécifique.
Polymorphisme constructeur ?
Le constructeur n'a pas de polymorphisme, car la méthode de construction elle-même est une méthode statique (sinon, elle tombera dans un cycle sans fin de poules pondant des œufs et d'œufs pondant). Pour présenter notre problème, regardons d'abord l'ordre dans lequel le constructeur est appelé.
1. L'espace de stockage alloué à cet objet est initialisé à 0 (l'objet est initialisé à null)
2. Le constructeur de la classe parent est appelé (cela garantit que les champs accédés dans le constructeur de la sous-classe sont appelés. sont initialisés)
3. Initialisation de la variable membre
4. Appel du constructeur de la sous-classe
Supposons maintenant que dans la deuxième étape, nous appelions une certaine méthode dans le constructeur de la classe parent, c'est la méthode polymorphe ? Regardons un exemple spécifique :
class shape { protected int perimeter=1; public shape() { draw(); print("shape created"); } public void draw() { print("draw shape "+perimeter); } } class triangle extends shape { int perimeter=3; public triangle() { print("triangle created"); } public void draw() { print("draw triangle "+perimeter); } public int getPerimeter() { return perimeter; } } public class Polymorphism { public static void main(String[] args) { shape s=new triangle(); } }
Nous pouvons voir que même si l'objet triangle n'a pas encore été construit, la méthode draw est toujours liée dynamiquement à la méthode draw du triangle. Notez également que la valeur du périmètre n'a pas été initialisée à 3, mais à 0.
Le résultat est que nous accédons aux champs de l'objet triangle avant qu'il ne soit initialisé. Par conséquent, dans les applications réelles, nous devons éviter d'appeler d'autres méthodes dans le constructeur, ou appeler uniquement des méthodes privées (qui ne seront pas héritées, donc ce problème ne se produira pas)
Plus de précautions d'utilisation du polymorphisme Java sont liées Veuillez payer attention au site PHP chinois pour les articles !