ポリモーフィズムは、カプセル化と継承に続くオブジェクト指向の 3 番目の主要な機能です。
ポリモーフィズムの実際的な重要性:
- 現実のものには複数の形式があることがよくあり、たとえば、学生、学生は一種の人間ですが、特定の学生シャオミンは学生でもあり、人間でもあり、つまり 2 つの形式があります。
- Java はオブジェクト指向言語として、1 つのものの複数の形式を記述することもできます。たとえば、Student クラスは Person クラスを継承し、Student オブジェクトは Student と Person の両方です。
- ポリモーフィズムは、親クラス変数がサブクラス オブジェクトを指すことができるという事実に反映されています (前提条件は親子関係が存在する必要があるということです)。
- 多態性の親クラス変数を使用してメソッドを呼び出すと、サブクラスによって書き換えられたメソッドが呼び出されます。
ポリモーフィズムの定義:父类类型 变量名 = new 子类类型();
ポリモーフィックな理解:
- ポリモーフィズムとは、同じ動作が複数の異なる発現または形式を持つ能力です。
- ポリモーフィズムは同じインターフェイスであり、異なるインスタンスを使用して異なる操作を実行します。
ポリモーフィズムにおけるメンバーの特徴:
- 多態性メンバー変数。コンパイルして実行して左を確認します。
Person p = new Student();
System.out.println(p.num); // num 是 Person 中的值
- 多態性メンバー メソッド: 左側にコンパイルし、右側に実行します。
Person p = new Student();
System.out.println(p.show()) // 调用的是 Student 中重写的方法
instanceof
キーワード: オブジェクトが特定のデータ型に属しているかどうかを判断するために使用され、戻り値の型はブール型です。
public class Test {
public static void main(String[] args) {
Person p = new Student();
if (p instanceof Student) {
System.out.println("p 是 Student 类型");
} else {
System.out.println("p 不是 Student 类型");
}
}
}
// p 是 Student 类型
ポリモーフィック変換: 上方変換と下方変換に分かれる
- 上方変換: ポリモーフィズム自体は上方変換のプロセスです
父类类型 变量 = new 子类类型()
。サブクラスの型に直面する必要がない場合、対応する操作は親クラスの関数を使用して完了できます。 - ダウンキャスト: アップキャストされたサブクラス オブジェクトは、強制型変換形式を使用して、親クラスの参照型をサブクラスの参照型に変換できます
子类类型 变量 = (子类类型)父类类型变量
。サブクラス固有の関数を使用する必要がある場合は、ダウンキャストを使用できます。
public class Test {
public static void main(String[] args) {
Person person = new Student();
person.eat(); // student eat
Student student = (Student) person;
student.study(); // student study
}
}
class Person {
public void eat() {
System.out.println("people eat");
}
}
class Student extends Person {
@Override
public void eat() {
System.out.println("student eat");
}
public void study() {
System.out.println("student study");
}
}
class Teacher extends Person {
@Override
public void eat() {
System.out.println("teacher eat");
}
public void teach() {
System.out.println("teacher teach");
}
}
すみません、質問を実行した結果はどうなりましたか?
public class Test {
public static void main(String[] args) {
Shape shape = new Shape();
shape.show(); // shape
Circle circle = new Circle();
circle.show(); // circle
CircularCone circularCone = new CircularCone();
circularCone.show(); // circular cone
}
}
class Shape {
public void show() {
showShape();
}
public void showShape() {
System.out.println("shape");
}
}
class Circle extends Shape {
@Override
public void showShape() {
System.out.println("circle");
}
}
class CircularCone extends Circle {
@Override
public void show() {
super.show();
}
@Override
public void showShape() {
System.out.println("circular cone");
}
}
ポリモーフィズムには 2 つのタイプがあります。
- コンパイル時のポリモーフィズム: メソッドのオーバーロード。
- ランタイムポリモーフィズム: Java ランタイム システムは、メソッドを呼び出すインスタンスのタイプに基づいて、どのメソッドを呼び出すかを決定します。
- オブジェクト指向の 3 つの主要な機能: カプセル化、継承、ポリモーフィズム。ある観点から見ると、カプセル化と継承はポリモーフィズムに対してほぼ準備が整っています。
- ポリモーフィズムの定義: 異なるオブジェクトが同じメッセージに応答できるようにすることを指します。つまり、同じメッセージが、異なる送信オブジェクトに応じて異なる動作を採用できる (メッセージは関数呼び出しです)。
- ポリモーフィズムを実現する技術は、ダイナミックバインディング(動的バインディング)と呼ばれ、実行中に参照先オブジェクトの実際の型を判断し、実際の型に応じて対応するメソッドを呼び出すことを指します。
ポリモーフィズムの役割: 型間の結合関係を排除すること。
ポリモーフィズムが存在するには、継承、書き換え、サブクラス オブジェクトを指す親クラス参照の 3 つの必要条件があります。
ポリモーフィズムの利点:
- 置換可能性: ポリモーフィズムは既存のコードと置換可能です。たとえば、ポリモーフィズムは Shape クラスだけでなく、Circle などの他の Shape にも機能します。
- 拡張性: ポリモーフィズムはコードに対して拡張可能です。新しいサブクラスを追加しても、ポリモーフィズム、継承、および既存のクラスの他の機能の操作や操作には影響しません。実際、新しいサブクラスを追加すると、ポリモーフィック機能に簡単にアクセスできます。たとえば、CircularCone (円錐) を実現した後は、半円錐を実現する方が簡単です。
- インターフェイス機能: ポリモーフィズムは、メソッド シグネチャを通じてサブクラスに共通のインターフェイスを提供するスーパークラスによって実現され、メソッド シグネチャはサブクラスによって完成または上書きされます。
- 柔軟性: アプリケーションで柔軟で多様な操作を実現し、実用的な効率を提供します。
- シンプルさ: ポリモーフィズムは、アプリケーション ソフトウェア コードの作成と変更のプロセスを簡素化します。特に、多数のオブジェクトの操作や操作を扱う場合、この機能は特に顕著で重要です。
デモ1:
上記の例では、Father のgetName()
メソッドがコメントアウトされている場合、father.getName()
メソッドを呼び出すとエラーが発生します。したがって、親クラスの参照がサブクラスのメソッドを指している場合、親クラスに存在するメソッドを呼び出す必要があります。メソッドがサブクラスでオーバーライドされると、サブクラスのメソッドは実行時に動的に呼び出されます。これはポリモーフィックです。次のように変更します。
public class Test {
public static void main(String[] args) {
Test test = new Test();
// 注意:采用此种方式创建实例,否则静态方法中只能创建静态内部类的实例
Test.Father father = test.new Son();
System.out.println(father.getName()); // son
}
public class Father {
private String name = "father";
public String getName() {
return this.name;
}
}
public class Son extends Father {
private String name = "son";
@Override
public String getName() {
return this.name;
}
}
}
出力son
。引き続き次の例を見てください。
public class Test {
public static void main(String[] args) {
Test test = new Test();
// 注意:采用此种方式创建实例,否则静态方法中只能创建静态内部类的实例
Test.Shape shape1 = test.new Shape();
Test.Shape shape2 = test.new Circle();
Test.Circle circle = test.new Circle();
Test.CircleCone circleCone = test.new CircleCone();
shape1.show(circle); // Shape and Shape
shape1.show(circleCone); // Shape and CircleCone
shape2.show(circle); // Circle and Shape
shape2.show(circleCone); // Shape and CircleCone
}
public class Shape {
public void show(Shape shape) {
System.out.println("Shape and Shape");
}
public void show(CircleCone circleCone) {
System.out.println("Shape and CircleCone");
}
}
public class Circle extends Shape {
public void show(Circle circle) {
System.out.println("Circle and Circle");
}
public void show(Shape shape) {
System.out.println("Circle and Shape");
}
}
public class CircleCone extends Circle {
public void show(CircleCone circleCone) {
System.out.println("CircleCone and CircleCone");
}
public void show(Circle circle) {
System.out.println("CircleCone and Circle");
}
}
}
shape2.show(circle)
印刷されているのはCircle and Shape
、なぜここではないのですかCircle and Circle
?これは、スーパークラス変数がサブクラス オブジェクトを参照する場合、変数の型ではなく、参照されるオブジェクトの型によって、呼び出されるメンバー メソッドが決定されるためです。ただし、呼び出されるメソッドはスーパークラスで定義されている必要があります。つまり、サブクラスによってオーバーライドされるメソッドです。
まず第一に、「スーパークラス変数がサブクラス オブジェクトを参照する場合、変数の型ではなく、参照されるオブジェクトの型によって、どのメンバー メソッドを呼び出すかが決まります。」これは、実行時に呼び出すことを決定するのはクラスであることを意味しますshape2.show(circle)
。Circle
誰の方法。ただし、その親クラスにはShape
メソッドが定義されていないshow(Circle circle)
ため、「サブクラスのカバレッジ」などというものはありません。したがって、ここにはメソッド呼び出しの優先順位が関係します。
優先順位は高から低の順で、this.show(O)
-> super.show(O)
-> this.show((super)O)
->となりますsuper.show((super)O)
。
shape2.show(circle)
はthis
を参照しますshape2
が、でメソッドがShape
見つからなかったので、には親クラスがないため、 の親クラスでそれを見つけに行き、その後 3 番目の優先順位の、依然として、つまりの親クラスに進みました。の、メソッドで検索、にこのメソッドがありますが、オブジェクトを指しており、メソッドは で書き換えられているため、最終的にメソッドが呼び出され、 が出力されます。show(Circle circle)
Shape
Shape
this.show((super)O)
this
shape2
O
Circle
(super)Circle
Circle
Shape
Shape
show(Shape shape)
Shape
shape2
Circle
Circle
show(Shape shape)
Circle.show(Shape shape)
Circle and Shape
次に、次の例を見てください。
public class Test {
public static void main(String[] args) {
Shape shape = new Circle();
shape.show(); // circle
Circle circle = new CircleCone();
circle.show(); // circle cone
}
}
class Shape {
public void show() {
show2();
}
public void show2() {
System.out.println("shape");
}
}
class Circle extends Shape {
public void show2() {
System.out.println("circle");
}
}
class CircleCone extends Circle {
public void show2() {
System.out.println("circle cone");
}
}
shape = new Circle()
を実行すると、クラスに定義されていない メソッドが呼び出されるため、のshape.show()
親クラスのメソッドが呼び出されます。サブクラスが実装したメソッド内でメソッドが呼び出されることになるので、サブクラスのメソッドが呼び出されます。Circle.show()
Circle
Circle
Shape.show()
Shape.show()
show2()
show2()