Heim  >  Artikel  >  Java  >  Analyse der Definition und Verwendung von Polymorphismus in Java

Analyse der Definition und Verwendung von Polymorphismus in Java

黄舟
黄舟Original
2017-09-28 10:01:231852Durchsuche

Dieser Artikel führt hauptsächlich in die Definition und Verwendung des Java-Polymorphismus ein. Er analysiert das Konzept und die Funktionen des Polymorphismus ausführlicher und erläutert die damit verbundenen Bedienfähigkeiten der Java-Definition und -Implementierung des objektorientierten Polymorphismus it

Die Beispiele in diesem Artikel beschreiben die Definition und Verwendung des Java-Polymorphismus. Teilen Sie es als Referenz mit allen. Die Details lauten wie folgt:

Polymorphismus erfolgt durch:

1 Schnittstelle und mehrere verschiedene Klassen, die die Schnittstelle implementieren und dieselbe abdecken Methode in der Schnittstelle Verkörpert

2, die übergeordnete Klasse und die Implementierung mehrerer verschiedener Unterklassen, die die übergeordnete Klasse erben und dieselbe Methode in der übergeordneten Klasse abdecken.

1. Grundkonzepte

Polymorphismus: Senden Sie eine Nachricht an ein Objekt und lassen Sie das Objekt entscheiden, auf welches Verhalten es reagieren soll. Der dynamische Methodenaufruf wird durch Zuweisen der Objektreferenz der Unterklasse zur Objektreferenzvariablen der Oberklasse implementiert.

Dieser Mechanismus von Java folgt einem Prinzip: Wenn eine Objektreferenzvariable der Oberklasse auf ein Unterklassenobjekt verweist, bestimmt der Typ des referenzierten Objekts und nicht der Typ der Referenzvariable, welche Mitgliedsmethode aufgerufen wird. Dies ist jedoch der Fall aufgerufen Die Methode muss in der Superklasse definiert werden, dh die Methode wird von der Unterklasse überschrieben.

Wenn a eine Referenz der Klasse A ist, kann a auf eine Instanz der Klasse A oder auf eine Unterklasse der Klasse A verweisen.

Wenn a ein Verweis auf Schnittstelle A ist, muss a auf eine Instanz einer Klasse verweisen, die Schnittstelle A implementiert.

2. Java-Polymorphismus-Implementierungsmechanismus

SUNs aktueller JVM-Implementierungsmechanismus, die Referenz einer Klasseninstanz zeigt auf einen Handle (Handle)-Zeiger , dieses Handle ist ein Zeigerpaar:

Ein Zeiger zeigt auf eine Tabelle. Tatsächlich hat diese Tabelle auch zwei Zeiger (ein Zeiger zeigt auf eine Methodentabelle, die Objekte enthält, und der andere zeigt auf ein Klassenobjekt , der den Typ des Objekts angibt);

Ein weiterer Zeiger zeigt auf einen vom Java-Heap zugewiesenen Speicherplatz.

3. Zusammenfassung

1. Der dynamische Methodenaufruf wird durch Zuweisen der Unterklassen-Objektreferenzvariable erreicht.


DerivedC c2=new DerivedC();
BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类
a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法

Analyse:

1. Warum können Objektinstanzen von Unterklassentypen durch Oberklassen überschrieben werden? ?

Automatisch eine Aufwärtstransformation realisieren. Durch diese Anweisung verschiebt der Compiler die Unterklasseninstanz automatisch nach oben und wird zum universellen Typ BaseClass

2. Wird a.play() die von der Unterklasse oder der übergeordneten Klasse definierte Methode ausführen?

Unterklasse von . Zur Laufzeit wird die entsprechende Methode basierend auf dem tatsächlichen Typ der Objektreferenz a abgerufen. Deshalb gibt es Polymorphismus. Wenn eine Basisklassen-Objektreferenz einer anderen Unterklassen-Objektreferenz zugewiesen wird, zeigt sie bei Ausführung der Methode ein anderes Verhalten.

Wenn a1 = c2, gibt es immer noch zwei Handles, a1 und c2, aber a1 und c2 haben denselben Datenspeicherblock und unterschiedliche Funktionstabellen.

2. Sie können die Objektreferenz der übergeordneten Klasse nicht der Objektreferenzvariablen der Unterklasse zuweisen


BaseClass a2=new BaseClass();
DerivedC c1=a2;//出错

In Java, up Die Transformation erfolgt automatisch, die Abwärtstransformation jedoch nicht. Wir müssen sie selbst definieren und erzwingen.

c1=(DerivedC)a2; Führen Sie eine erzwungene Konvertierung durch, also eine Abwärtskonvertierung

3. Denken Sie an eine sehr einfache, aber komplexe Regel: Eine Typreferenz kann sich nur auf den Referenztyp selbst beziehen Methoden und Variablen.

Man könnte sagen, dass diese Regel falsch ist, denn wenn die Referenz der übergeordneten Klasse auf das Unterklassenobjekt verweist, wird die Methode der Unterklasse schließlich ausgeführt.

Tatsächlich ist dies kein Widerspruch. Dies liegt daran, dass die späte Bindung verwendet wird und die Unterklassenmethode während des dynamischen Betriebs entsprechend dem Typ aufgerufen wird. Und wenn diese Methode der Unterklasse nicht in der übergeordneten Klasse definiert ist, tritt ein Fehler auf.

Zusätzlich zum Erben der in BaseClass definierten Funktionen fügt die DerivedC-Klasse beispielsweise auch mehrere Funktionen hinzu (z. B. myFun())

Analyse:

Wenn Sie einen Verweis auf eine übergeordnete Klasse verwenden, um auf eine Unterklasse zu verweisen, hat der JVM tatsächlich die vom Compiler generierten Typinformationen verwendet, um die Konvertierung anzupassen.

Sie können es so verstehen, dass es gleichbedeutend damit ist, Funktionen, die nicht in der übergeordneten Klasse enthalten sind, in der virtuellen Funktionstabelle auf unsichtbar zu setzen. Beachten Sie, dass möglicherweise einige Funktionsadressen in der virtuellen Funktionstabelle in der Unterklasse neu geschrieben wurden, sodass die Adresse des virtuellen Funktionselements in der virtuellen Funktionstabelle des Objekts auf die Adresse des in der Unterklasse abgeschlossenen Methodenkörpers gesetzt wurde.

4. Vergleich des Polymorphismus zwischen Java und C++

JVMs Polymorphismus-Unterstützungslösung ist fast die gleiche wie die in C++, außer dass es in C++ viele Compiler gibt sowohl Typinformationen als auch Informationen zu virtuellen Funktionen in einer virtuellen Funktionstabelle, verwendet jedoch eine Technologie, um sie zu unterscheiden.

Java trennt Typinformationen und Funktionsinformationen. Nach der Vererbung in Java setzt die Unterklasse ihre eigene virtuelle Funktionstabelle zurück. Die Elemente in dieser virtuellen Funktionstabelle bestehen aus zwei Teilen. Virtuelle Funktionen, die von den eigenen virtuellen Funktionen der übergeordneten Klasse und der Unterklasse geerbt wurden.

Virtuelle Funktionsaufrufe werden indirekt über die virtuelle Funktionstabelle aufgerufen, sodass Polymorphismus erreicht werden kann. Alle Funktionen in Java, mit Ausnahme derjenigen, die als final deklariert wurden, verwenden die späte Bindung.

四. 1个行为,不同的对象,他们具体体现出来的方式不一样,

比如: 方法重载 overloading 以及 方法重写(覆盖)override


class Human{
void run(){输出 人在跑}
}
class Man extends Human{
void run(){输出 男人在跑}
}

这个时候,同是跑,不同的对象,不一样(这个是方法覆盖的例子)


class Test{
void out(String str){输出 str}
void out(int i){输出 i}
}

这个例子是方法重载,方法名相同,参数表不同

ok,明白了这些还不够,还用人在跑举例


Human ahuman=new Man();

这样我等于实例化了一个Man的对象,并声明了一个Human的引用,让它去指向Man这个对象

意思是说,把 Man这个对象当 Human看了.

比如去动物园,你看见了一个动物,不知道它是什么, “这是什么动物? ” “这是大熊猫! “

这2句话,就是最好的证明,因为不知道它是大熊猫,但知道它的父类是动物,所以,这个大熊猫对象,你把它当成其父类 动物看,这样子合情合理.这种方式下要注意 new Man();的确实例化了Man对象,所以ahuman.run()这个方法 输出的 是 “男人在跑 “如果在子类 Man下你 写了一些它独有的方法 比如 eat(),而Human没有这个方法,在调用eat方法时,一定要注意 强制类型转换 ((Man)ahuman).eat(),这样才可以…

对接口来说,情况是类似的…


package domatic;
//定义超类superA
class superA {
int i = 100;
void fun(int j) {
j = i;
System.out.println("This is superA");
}
}
// 定义superA的子类subB
class subB extends superA {
int m = 1;
void fun(int aa) {
System.out.println("This is subB");
}
}
// 定义superA的子类subC
class subC extends superA {
int n = 1;
void fun(int cc) {
System.out.println("This is subC");
}
}
class Test {
public static void main(String[] args) {
superA a = new superA();
subB b = new subB();
subC c = new subC();
a = b;
a.fun(100);
a = c;
a.fun(200);
}
}


/*
* 上述代码中subB和subC是超类superA的子类,我们在类Test中声明了3个引用变量a, b,
* c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用 。也许有人会问:
* “为什么(1)和(2)不输出:This is superA” 。
* java的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,
* 被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,
* 但是这个被调用的方法必须是在超类中定义过的,
* 也就是说被子类覆盖的方法 。
* 所以,不要被上例中(1)和(2)所迷惑,虽然写成a.fun(),但是由于(1)中的a被b赋值,
* 指向了子类subB的一个实例,因而(1)所调用的fun()实际上是子类subB的成员方法fun(),
* 它覆盖了超类superA的成员方法fun();同样(2)调用的是子类subC的成员方法fun() 。
* 另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,
* 但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性 。具体的实现方法同上例 。
* 不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,
* 否则子类必须被abstract修饰符修饰,当然也就不能被实例化了
*/

以上大多数是以子类覆盖父类的方法实现多态.下面是另一种实现多态的方法———–重写父类方法

1.JAVA里没有多继承,一个类之能有一个父类 。而继承的表现就是多态 。一个父类可以有多个子类,而在子类里可以重写父类的方法(例如方法print()),这样每个子类里重写的代码不一样,自然表现形式就不一样 。这样用父类的变量去引用不同的子类,在调用这个相同的方法print()的时候得到的结果和表现形式就不一样了,这就是多态,相同的消息(也就是调用相同的方法)会有不同的结果 。举例说明:


//父类
public class Father{
//父类有一个打孩子方法
public void hitChild(){
}
}
//子类1
public class Son1 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("为什么打我?我做错什么了!");
}
}
//子类2
public class Son2 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我知道错了,别打了!");
}
}
//子类3
public class Son3 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我跑,你打不着!");
}
}
//测试类
public class Test{
public static void main(String args[]){
Father father;
father = new Son1();
father.hitChild();
father = new Son2();
father.hitChild();
father = new Son3();
father.hitChild();
}
}

都调用了相同的方法,出现了不同的结果!这就是多态的表现!

Das obige ist der detaillierte Inhalt vonAnalyse der Definition und Verwendung von Polymorphismus in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn