Java-Polymorphismus


Polymorphismus ist die Fähigkeit, dass dasselbe Verhalten mehrere verschiedene Formen oder Erscheinungsformen annehmen kann.

Polymorphismus ist dieselbe Schnittstelle, wobei verschiedene Instanzen unterschiedliche Operationen ausführen, wie in der Abbildung dargestellt:

Polymorphismus ist die Manifestation von Objekten in mehreren Formen.

Im wirklichen Leben zum Beispiel die Aktion des Drückens der F1-Taste:

  • Wenn Sie sich derzeit in der Flash-Oberfläche befinden, wird die AS 3 Hilfe-Dokumentation angezeigt;
  • Wenn Sie sich derzeit in Word befinden, wird die Word-Hilfe angezeigt;
  • Unter Windows wird die Windows-Hilfe und Support angezeigt.

Dasselbe Ereignis, das auf verschiedenen Objekten auftritt, erzeugt unterschiedliche Ergebnisse.

Vorteile von Polymorphismus

  • 1. Kopplungsbeziehungen zwischen Typen beseitigen
  • 2. Austauschbarkeit
  • 3. 可扩展性
  • 4. Schnittstellenfähigkeit
  • 5. Flexibilität
  • 6. Vereinfachung

Drei notwendige Bedingungen für Polymorphismus

  • Vererbung
  • Überschreiben
  • Eine Referenz auf die Elternklasse zeigt auf ein Objekt der Unterklasse:Parent p = new Child();

class Shape {
    void draw() {}
}
 
class Circle extends Shape {
    void draw() {
        System.out.println("Circle.draw()");
    }
}
 
class Square extends Shape {
    void draw() {
        System.out.println("Square.draw()");
    }
}
 
class Triangle extends Shape {
    void draw() {
        System.out.println("Triangle.draw()");
    }
}

Wenn eine Methode unter Verwendung von Polymorphismus aufgerufen wird, prüfe zuerst, ob die Elternklasse diese Methode besitzt. Wenn nicht, tritt ein Kompilierungsfehler auf; wenn doch, rufe die Methode der Unterklasse mit demselben Namen auf.

Vorteil des Polymorphismus: Er kann Programmen eine gute Erweiterbarkeit verleihen und es ermöglichen, alle Klassenobjekte generisch zu behandeln.

Das Folgende ist eine Demonstration eines polymorphen Beispiels. Für eine ausführliche Erklärung siehe bitte die Kommentare:

Code der Datei Test.java:

public class Test { public static void main(String[] args) { show(new Cat()); //Rufe die show-Methode mit einem Cat-Objekt auf show(new Dog()); //Rufe die show-Methode mit einem Dog-Objekt auf Animal a = new Cat(); //Upcasting a.eat(); //Ruft die eat-Methode von Cat auf Cat c = (Cat)a; //Downcasting c.work(); //Ruft die work-Methode von Cat auf } public static void show(Animal a) { a.eat(); //Typüberprüfung if (a instanceof Cat) { //Dinge, die Katzen tun Cat c = (Cat)a; c.work(); } else if (a instanceof Dog) { //Dinge, die Hunde tun Dog c = (Dog)a; c.work(); } } } abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("Fisch fressen"); } public void work() { System.out.println("Mäuse fangen"); } } class Dog extends Animal { public void eat() { System.out.println("Knochen fressen"); } public void work() { System.out.println("Das Haus bewachen"); } }

Führen Sie das obige Programm aus, das Ausgabeergebnis ist:

eat fish
catch mice
eat bones
guard the house
eat fish
catch mice

Virtuelle Funktionen

Virtuelle Funktionen existieren für Polymorphie.

Java hat eigentlich kein Konzept von virtuellen Funktionen. Seine gewöhnlichen Funktionen entsprechen C++-virtuellen Funktionen, und dynamische Bindung ist das Standardverhalten in Java. Wenn Sie nicht möchten, dass eine Funktion in Java virtuelle Funktionsmerkmale aufweist, können Sie das Schlüsselwort final hinzufügen, um sie zu einer nicht-virtuellen Funktion zu machen.

Überschreiben

Wir werden erläutern, wie sich das Verhalten überschriebener Methoden auf die Polymorphie beim Entwerfen von Klassen in Java auswirkt.

Wir haben bereits das Überschreiben von Methoden besprochen, das heißt, Unterklassen können Methoden der Elternklasse überschreiben.

Wenn ein Objekt einer Unterklasse eine überschriebene Methode aufruft, ruft es die Methode der Unterklasse auf, nicht die überschriebene Methode in der Oberklasse.

Um die überschriebene Methode in der Oberklasse aufzurufen, müssen Sie das Schlüsselwortsuper verwenden。

Code der Datei Employee.java:

/*Dateiname : Employee.java*/ public class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Employee-Konstruktor"); this.name = name; this.address = address; this.number = number; } public void mailCheck() { System.out.println("Sende Post an:" + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } }

Angenommen, die folgende Klasse erbt von der Klasse Employee:

Code der Datei Salary.java:

/*Dateiname : Salary.java*/ public class Salary extends Employee { private double salary; //Jahresgehalt public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("mailCheck-Methode der Klasse Salary"); System.out.println("Scheck senden an:" + getName() + ", Gehalt:" + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Gehalt berechnen, auszahlen an:" + getName()); return salary/52; } }

Jetzt lesen wir den folgenden Code sorgfältig und versuchen, sein Ausgabeergebnis anzugeben:

Code der Datei VirtualDemo.java:

/*Dateiname: VirtualDemo.java*/ public class VirtualDemo { public static void main(String [] args) { Salary s = new Salary("Mitarbeiter A", "Beijing", 3, 3600.00); Employee e = new Salary("Mitarbeiter B", "Shanghai", 2, 2400.00); System.out.println("Aufruf von mailCheck mit Salary-Referenz --"); s.mailCheck(); System.out.println("\nAufruf von mailCheck mit Employee-Referenz--"); e.mailCheck(); } }

Das Kompilierungs- und Ausführungsergebnis des obigen Beispiels ist wie folgt:

Employee 构造函数
Employee 构造函数
使用 Salary 的引用调用 mailCheck -- 
Salary 类的 mailCheck 方法 
邮寄支票给:员工 A ,工资为:3600.0

使用 Employee 的引用调用 mailCheck--
Salary 类的 mailCheck 方法 
邮寄支票给:员工 B ,工资为:2400.0

Beispielanalyse

  • Im Beispiel werden zwei Salary-Objekte instanziiert: eines mit der Salary-Referenz s und das andere mit der Employee-Referenz e.

  • Beim Aufruf von s.mailCheck() findet der Compiler mailCheck() zur Compile-Zeit in der Klasse Salary, und während der Ausführung ruft die JVM mailCheck() der Klasse Salary auf.

  • e ist eine Employee-Referenz, aber die Referenz e führt letztendlich die Methode mailCheck() der Klasse Salary aus.

  • Zur Compile-Zeit verwendet der Compiler die Methode mailCheck() in der Klasse Employee, um die Anweisung zu validieren, aber zur Laufzeit ruft die Java Virtual Machine (JVM) die Methode mailCheck() in der Klasse Salary auf.

Der gesamte oben beschriebene Vorgang wird als virtueller Methodenaufruf bezeichnet, und die Methode wird als virtuelle Methode bezeichnet.

Alle Methoden in Java können sich auf diese Weise verhalten. Daher können überschriebene Methoden zur Laufzeit aufgerufen werden, unabhängig davon, welchen Datentyp die Referenzvariable zur Compile-Zeit im Quellcode hat.


Möglichkeiten zur Implementierung von Polymorphie

Methode 1: Überschreiben:

Dieser Inhalt wurde bereits im vorherigen Kapitel ausführlich behandelt, daher wird er hier nicht weiter erläutert. Für Details besuchen Sie bitte:Java-Überschreiben und Überladen。

Methode 2: Schnittstellen

  • 1. Die repräsentativste Schnittstelle im Leben ist eine Steckdose. Zum Beispiel kann ein Stecker mit drei Stiften in eine Steckdose mit drei Löchern gesteckt werden, weil jedes Land seine eigenen Schnittstellenregeln hat. Im Ausland funktioniert er möglicherweise nicht, weil fremde Länder ihre eigenen Schnittstellentypen definieren.

  • 2. Eine Schnittstelle in Java ähnelt einer Schnittstelle im Leben; sie ist eine Sammlung von Methodensignaturen, aber ohne Methodenimplementierungen. Für Details sieheJava-Schnittstellenin diesem Kapitel.

Methode 3: Abstrakte Klassen und abstrakte Methoden

Für Details sieheJava Abstract ClassesKapitel.

Andere Erweiterungen