Maison > Java > javaDidacticiel > Explication détaillée de la conversion de type et de la liaison dynamique des objets polymorphes Java

Explication détaillée de la conversion de type et de la liaison dynamique des objets polymorphes Java

高洛峰
Libérer: 2017-01-19 13:45:26
original
1355 Les gens l'ont consulté

Conversion de type d'objets polymorphes Java
La conversion de type d'objet mentionnée ici fait référence à des objets avec des relations d'héritage, et non à des objets d'aucun type. Lors de la conversion d'un objet qui n'a pas de relation d'héritage, le moteur d'exécution Java lèvera une exception java.lang.ClassCastException.

Dans la chaîne d'héritage, nous appelons la conversion d'une sous-classe en classe parent "upcasting", et la conversion d'une classe parent en classe enfant est appelée "downcasting".

Souvent, nous définirons les variables comme le type de la classe parent, mais nous nous référerons à l'objet de la sous-classe. Ce processus est une transformation vers le haut. Lorsque le programme est en cours d'exécution, l'appel des méthodes de sous-classe est implémenté via une liaison dynamique, qui est le polymorphisme.

Cependant, parfois, afin de compléter certaines fonctions que la classe parent n'a pas, nous devons convertir l'objet de sous-classe après transformation ascendante en sous-classe et appeler la méthode de la sous-classe.

Remarque : vous ne pouvez pas forcer directement l'objet de la classe parent au type de sous-classe. Vous pouvez uniquement reconvertir l'objet de sous-classe upcast en type de sous-classe. En d’autres termes, les objets de sous-classe doivent être transformés vers le haut avant de pouvoir être transformés vers le bas. Veuillez regarder le code suivant :

public class Demo {
  public static void main(String args[]) {
    SuperClass superObj = new SuperClass();
    SonClass sonObj = new SonClass();
    // 下面的代码运行时会抛出异常,不能将父类对象直接转换为子类类型
    // SonClass sonObj2 = (SonClass)superObj;
    // 先向上转型,再向下转型
    superObj = sonObj;
    SonClass sonObj1 = (SonClass)superObj;
  }
}
class SuperClass{ }
class SonClass extends SuperClass{ }
Copier après la connexion

Supprimez le commentaire sur la ligne 7. Une exception sera levée lors de l'exécution, mais la compilation peut réussir.

Comme il existe des risques lors du downcasting, lorsque vous recevez une référence de la classe parent, assurez-vous d'utiliser l'opérateur instanceof pour déterminer si l'objet est la sous-classe souhaitée. Veuillez consulter le code suivant :

<. 🎜>
public class Demo {
  public static void main(String args[]) {
    SuperClass superObj = new SuperClass();
    SonClass sonObj = new SonClass();
    // superObj 不是 SonClass 类的实例
    if(superObj instanceof SonClass){
      SonClass sonObj1 = (SonClass)superObj;
    }else{
      System.out.println("①不能转换");
    }
    superObj = sonObj;
    // superObj 是 SonClass 类的实例
    if(superObj instanceof SonClass){
      SonClass sonObj2 = (SonClass)superObj;
    }else{
      System.out.println("②不能转换");
    }
  }
}
class SuperClass{ }
class SonClass extends SuperClass{ }
Copier après la connexion
Résultat de l'exécution :

①不能转换
Copier après la connexion

Résumé : La conversion de type de l'objet est vérifiée lors de l'exécution du programme. La conversion ascendante doit être effectuée automatiquement. Une sous-classe du type de référence actuel.

Polymorphisme Java et liaison dynamique

En Java, les variables d'une classe parent peuvent référencer des instances de la classe parent ou des instances de la sous-classe.

Veuillez d'abord lire un morceau de code :

public class Demo {
  public static void main(String[] args){
    Animal obj = new Animal();
    obj.cry();
    obj = new Cat();
    obj.cry();
    obj = new Dog();
    obj.cry();
  }
}
class Animal{
  // 动物的叫声
  public void cry(){
    System.out.println("不知道怎么叫");
  }
   
}
class Cat extends Animal{
  // 猫的叫声
  public void cry(){
    System.out.println("喵喵~");
  }
}
class Dog extends Animal{
  // 狗的叫声
  public void cry(){
    System.out.println("汪汪~");
  }
}
Copier après la connexion

Résultat d'exécution :

不知道怎么叫
喵喵~
汪汪~
Copier après la connexion

Le code ci-dessus , Trois classes sont définies, à savoir Animal, Cat et Dog. Les classes Cat et Dog héritent de la classe Animal. La variable obj est de type Animal et elle peut pointer soit vers une instance de la classe Animal, soit vers une instance des classes Cat et Dog, ce qui est correct. En d’autres termes, les variables de la classe parent peuvent faire référence à des instances de la classe parent ou à des instances de la sous-classe. Notez que l’inverse est faux car tous les chats sont des animaux, mais tous les animaux ne sont pas des chats.

On voit que obj peut être un humain, un chat ou un chien. Il a différentes expressions, ce qu'on appelle le polymorphisme. Le polymorphisme signifie qu'une chose a différentes manifestations ou formes.

Un autre exemple est « être humain ». Il existe de nombreuses expressions ou réalisations différentes. TA peut être un conducteur, un enseignant, un médecin, etc. Lorsque vous vous détestez, vous direz « devenez une nouvelle personne dans votre prochain ». vie", alors vous deviendrez chauffeur ou enseignant dans votre prochaine vie. , les médecins peuvent le faire, on dit juste que "les êtres humains" ont du polymorphisme.

Il existe trois conditions nécessaires à l'existence du polymorphisme : l'héritage, la substitution et les variables de classe parent font référence à des objets de sous-classe.

Lors de l'appel d'une méthode en utilisant le polymorphisme :

Vérifiez d'abord si la méthode existe dans la classe parent. Sinon, une erreur de compilation se produit si c'est le cas, vérifiez si la sous-classe remplace la méthode.
Si la sous-classe remplace cette méthode, appelez la méthode de la sous-classe, sinon appelez la méthode de la classe parent.

Comme le montre l'exemple ci-dessus, l'un des avantages du polymorphisme est le suivant : lorsqu'il existe de nombreuses sous-classes, il n'est pas nécessaire de définir plusieurs variables. Vous ne pouvez définir qu'une variable du type de classe parent à laquelle faire référence. différentes sous-classes. Veuillez regarder à nouveau l'exemple suivant :

public class Demo {
  public static void main(String[] args){
    // 借助多态,主人可以给很多动物喂食
    Master ma = new Master();
    ma.feed(new Animal(), new Food());
    ma.feed(new Cat(), new Fish());
    ma.feed(new Dog(), new Bone());
  }
}
// Animal类及其子类
class Animal{
  public void eat(Food f){
    System.out.println("我是一个小动物,正在吃" + f.getFood());
  }
}
class Cat extends Animal{
  public void eat(Food f){
    System.out.println("我是一只小猫咪,正在吃" + f.getFood());
  }
}
class Dog extends Animal{
  public void eat(Food f){
    System.out.println("我是一只狗狗,正在吃" + f.getFood());
  }
}
// Food及其子类
class Food{
  public String getFood(){
    return "事物";
  }
}
class Fish extends Food{
  public String getFood(){
    return "鱼";
  }
}
class Bone extends Food{
  public String getFood(){
    return "骨头";
  }
}
// Master类
class Master{
  public void feed(Animal an, Food f){
    an.eat(f);
  }
}
Copier après la connexion

Résultat d'exécution :

我是一个小动物,正在吃事物
我是一只小猫咪,正在吃鱼
我是一只狗狗,正在吃骨头
Copier après la connexion

La méthode d'alimentation de la classe Master a deux Les paramètres sont respectivement de type Animal et de type Food. Puisqu'il s'agit de classes parentes, des instances de sous-classes peuvent lui être transmises, de sorte que la classe Master n'a pas besoin de plusieurs méthodes pour nourrir différents animaux.

Liaison dynamique

Afin de comprendre la nature du polymorphisme, parlons du processus détaillé d'appel de méthodes en Java.

1) Le compilateur examine le type déclaré et le nom de méthode de l'objet.

Supposons que obj.func(param) soit appelé et que obj soit un objet de la classe Cat. Il convient de noter qu'il peut exister plusieurs méthodes nommées func mais avec des signatures de paramètres différentes. Par exemple, il peut y avoir des méthodes func(int) et func(String). Le compilateur énumérera toutes les méthodes nommées func dans la classe Cat et les méthodes nommées func dans sa classe parent Animal dont les propriétés d'accès sont publiques.

De cette manière, le compilateur obtient une liste de toutes les méthodes candidates pouvant être appelées.

2) Ensuite, le compilateur vérifiera les signatures de paramètres fournies lors de l'appel de la méthode.

Si parmi toutes les méthodes nommées func, il y en a une qui correspond exactement à la signature du paramètre fourni, alors cette méthode est sélectionnée. Ce processus est appelé résolution de surcharge. Par exemple, si vous appelez func("hello"), le compilateur choisira func(String) au lieu de func(int). En raison de l'existence d'une conversion de type automatique, par exemple, int peut être converti en double Si une méthode avec la même signature que le paramètre de la méthode appelante n'est pas trouvée, la conversion de type sera effectuée et la recherche se poursuivra si elle existe. aucun type correspondant à la fin ou il existe plusieurs méthodes qui lui correspondent, alors il y a une erreur de compilation.

De cette manière, le compilateur obtient le nom de la méthode et la signature du paramètre qui doit être appelé.

3) Si le modificateur de la méthode est private, static, final (static et final seront expliqués plus tard), ou une méthode constructeur, alors le compilateur saura exactement quelle méthode doit être appelée. Nous appellerons cette méthode C'est. appelée liaison statique.

En conséquence, la méthode appelée dépend du type réel de l'objet et est liée dynamiquement au moment de l'exécution. Par exemple, lorsque func("hello") est appelé, l'éditeur utilisera une liaison dynamique pour générer une instruction permettant d'appeler func(String).

4) Lorsque le programme est en cours d'exécution et qu'une méthode est appelée à l'aide d'une liaison dynamique, la JVM appellera certainement la méthode de la classe la plus adaptée au type réel de l'objet référencé par obj. Nous avons supposé que le type réel d'obj est Cat, qui est une sous-classe d'Animal, et si func(String) est défini dans Cat, il sera appelé, sinon il sera recherché dans la classe Animal et sa classe parent.

Chaque fois qu'une méthode est appelée, une recherche est requise, ce qui prend beaucoup de temps. Par conséquent, la JVM pré-crée une table de méthodes (étiquette de méthode) pour chaque classe, qui répertorie les noms et les signatures des paramètres. et La classe à laquelle il appartient. De cette façon, lorsque la méthode est réellement appelée, la machine virtuelle n’a qu’à consulter cette table. Dans l'exemple ci-dessus, la JVM recherche dans la table des méthodes de la classe Cat une méthode qui correspond à un appel à func("hello"). Cette méthode peut être Cat.func(String) ou Animal.func(String). Notez que si vous appelez super.func("hello"), le compilateur recherchera la table des méthodes de la classe parent.

Supposons que la classe Animal contienne trois méthodes : cry(), getName() et getAge(), alors sa table de méthodes est la suivante :
cry() ->
getName () -> Animal.getName()
getAge() -> Animal.getAge()

En fait, Animal a également une classe parent par défaut Object (cela sera expliqué plus tard ), qui héritera des méthodes Object, les méthodes répertoriées ci-dessus ne sont donc pas complètes.

Supposons que la classe Cat couvre la méthode cry() dans la classe Animal et ajoute une nouvelle méthode GrimTree(), alors sa liste de paramètres est :
cry() ->
getName() -> Animal.getName()
getAge() -> Animal.getAge()
climbTree() -> en cours d'exécution, le processus d'appel de la méthode obj.cry() est le suivant :

JVM accède d'abord à la table des méthodes du type réel d'obj, qui peut être la table des méthodes de la classe Animal, ou la table des méthodes de la classe Animal. Classe Cat et ses sous-classes.

La JVM recherche une méthode correspondant à cry() dans la table des méthodes. Une fois trouvée, elle sait à quelle classe elle appartient.
JVM appelle cette méthode.

Pour des articles plus détaillés sur la conversion de type et la liaison dynamique des objets polymorphes Java, veuillez faire attention au site Web PHP chinois !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal