著者:Sun Yuchang、愛称「イーイー兄」、「イーイー兄」も私です
Qianfeng Education の上級教育研究員、CSDN ブログ エキスパート、Wanfan ブロガー、Alibaba Cloud エキスパート ブロガー、高品質 Nuggets 著者
序文
前の 2 つの記事で、ブラザー イーはオブジェクト指向におけるカプセル化と継承について説明しましたが、ここでは私がまだ触れていないポリモーフィズムがもう 1 つあります。ただし、ポリモーフィズムを学ぶ前に、メソッドの書き換えがポリモーフィズムの必須条件であるため、「メソッドの書き換え」とは何かを事前に知っておく必要があります。したがって、メソッドの書き換えとは何なのかを知らなければ、ポリモーフィズムを学ぶのは少し大変になるでしょう。くだらないことはやめて、乾物を求めて直行してください!
--------------------------------------------------前戯は終わり、お楽しみが始まります-------------------------------------- -----
全文は約 [ 4000]語で、ナンセンスではなく、技術を学び原理を理解するための純粋なドライグッズです。この記事には豊富な事例と写真付きのビデオが含まれているため、記事内の技術的な概念をよりよく理解して使用することができ、十分な啓発的な思考を得ることができます。
オープンソースプロジェクト情報のサポート
ギットハブ:
ギティ:
1. メソッドの書き換え
オブジェクト指向では、ポリモーフィズムの前提条件は継承、書き換え、および上方変換です。これで、継承とは何かを学びました。次に、ポリモーフィズムを実現するための前提となるメソッド書き換えとは何なのかを学びましょう。
1.コンセプト
親クラスと同じ名前、戻り値の型、パラメータリストを持つメソッドをサブクラスに作成するが、メソッド本体の機能が異なる場合、このメソッドはメソッド オーバーライド (override )または Calledメソッド オーバーライドと呼ばれます。親クラスのメソッドがサブクラスのニーズを満たせない場合、またはサブクラスに特別な関数が必要な場合、メソッドの書き換えを実行できます。
2. 基本要件
メソッドを書き直すときは、次の要件に従う必要があります。
- 親クラスのメンバー メソッドは、そのサブクラスによってのみ書き換えることができます。つまり、メソッドを継承できない場合、このメソッドを書き換えることはできません。
- Final によって変更されたメソッドはオーバーライドできません。
- static によって変更されたメソッドはオーバーライドできませんが、再度宣言することはできます。
- コンストラクターをオーバーライドすることはできません。
- サブクラスと親クラスが同じパッケージ内にある場合、サブクラスは、private および Final によって変更されたメソッドを除く、親クラスのすべてのメソッドをオーバーライドできます。
- サブクラスと親クラスが同じパッケージ内にない場合、サブクラスは public および protected によって変更された親クラスの非finalメソッドのみを書き換えることができます。
- オーバーライドされたメソッドを識別するには @Override アノテーションを使用することをお勧めします。
3. 注意事項
また、メソッドを書き換える際には、次の点にも注意する必要があります。
- メソッドのシグネチャは同じである必要があります。オーバーライドされたメソッドとオーバーライドされたメソッドは同じメソッド名とパラメーターを持つ必要があります。
- 戻り値の型は同じです。JDK 1.5 より前に書き直されたメソッドの戻り値の型は同じである必要がありますが、新しい Java バージョンでは制限が緩和され、戻り値の型は JDK 1.5 の戻り値の型以下である必要があります。親メソッド;
- アクセス修飾子の幅が広い: サブクラスが親クラスのメソッドをオーバーライドする場合、サブクラスのメソッドのアクセス修飾子は親クラスのアクセス修飾子よりも厳密にすることはできません (public>protected>default>private)。たとえば、親クラス メソッドの修飾子が保護されている場合、同じ名前を持つサブクラス メソッドの修飾子は保護またはパブリックにすることができますが、デフォルトやプライベートにすることはできません。
- 宣言された例外の型は一貫している必要があります。オーバーライドされたメソッドは、新しいチェック例外や、オーバーライドされたメソッドの宣言よりも幅の広いチェック例外をスローしてはなりません。たとえば、親クラスのメソッドが IOException を宣言している場合、メソッドを書き換えたときに Exception をスローすることはできません。スローできるのは IOException またはそのサブクラスの例外のみですが、チェックされていない例外はスローできます。
4. コードの実装
次に、Brother Yi がケースを使ってメソッド書き換えの実装方法を説明します。
4.1 親クラスの定義
まず、Father 親クラスを定義し、親クラス内のどのメソッドがオーバーライドできないかに注目しましょう。
public class Father {
// 父类中的成员变量--变量隐藏
String name="老子";
//构造方法不能被重写,因为构造方法不能被继承!
public Father() {
System.out.println("爹的构造方法");
}
// 吃
public void eat() {
System.out.println("爹吃馒头");
}
// 喝
public void drink() {
System.out.println("爹喝水");
}
// 玩
//私有方法不能被重写
// private void play() {
// System.out.println("爹玩火");
// }
//静态方法不能被重写,但可以在子类中声明一个同样的静态方法。
// public static void play() {
// System.out.println("爹玩火");
// }
//final方法不能被重写
public final void play() {
System.out.println("爹玩火");
}
}
4.2 サブクラスの定義
Son サブクラスを定義して親クラスを継承します。継承を使用する場合のみ書き換えが可能です。
public class Son extends Father{
//构造方法不能被重写,因为构造方法不能被继承!
//@Override
//public Father() {}
// 吃
/**
* 方法重写时可以带有@Ovriride关键词,当重写的方法签名不一致时,可以有编译错误的提示。
* 否则方法签名不一致时不会有错误提示,会被当做一个新的方法来处理。
*/
@Override
public void eat() {
//如果子类的功能,是在父类的基础之上进行的额外扩展增加,
//我们可以使用super关键字调用父类的同名方法,然后再进行自己的额外扩展!
//如果子类的实现和父类完全不一样,可以不调用super!
super.eat();
//方法重写时,子类可以对父类的同名方法进行扩展实现,方法体的内容可以和父类中的实现不一样
System.out.println("儿子吃肉");
}
// 喝
@Override
public void drink() {
//如果子类的实现和父类完全不一样,可以不调用super!
System.out.println("儿子喝酒");
}
/**
* 父类私有的、static、final等方法无法被重写
*/
//@Override
//public void play() {}
//static静态的父类方法不能被重写,但可以在子类中再重新编写一个静态的同名方法。
//public static void play() {}
//变量隐藏--调用父类和子类中的同名成员变量
public void sayHello() {
// 如果子类的实现和父类完全不一样,可以不调用super!
System.out.println("父亲的名字=" + super.name);
System.out.println("儿子的名字=" + name);
}
public static void main(String[] args) {
Son son = new Son();
son.sayHello();
}
}
メソッドを書き直すときは、次の点に注意する必要があります。
- このメソッドは @Ovriride キーワードを使用して書き換えることができます。書き換えられたメソッド シグネチャが矛盾している場合は、コンパイル エラー プロンプトが表示されます。それ以外の場合、メソッド シグネチャが矛盾している場合はエラー プロンプトは表示されず、新しいメソッドとして扱われます。
- サブクラス オブジェクトがオーバーライドされたメソッドを呼び出すと、親クラスのオーバーライドされたメソッドではなく、サブクラス メソッドがデフォルトで実行されます。親クラスでオーバーライドされたメソッドを呼び出したい場合は、「super.メソッド名」の形式を使用できます。
- サブクラスの関数が親クラスに基づいた追加の拡張機能である場合、 super キーワードを使用して親クラスの同じ名前のメソッドを呼び出し、独自の追加の拡張機能を作成できます。
- サブクラスの実装が親クラスと完全に異なる場合は、super! を呼び出す必要はありません。
- メソッドが書き換えられると、サブクラスは親クラスの同じ名前のメソッドの実装を拡張することができ、メソッド本体の内容は親クラスの実装と異なる場合があります。
4.3 @Override アノテーション
上記のコードでは、新しいキーワード @Override を使用しました。Java では、@Override はアノテーションです。アノテーションの詳細については、Yige が後の記事で説明します。今のところ、アノテーションの概念だけを理解する必要があります。
@Override は、リワークされたメソッドを装飾するために使用されるアノテーションであり、リワークされたメソッドでのみ使用でき、他の場所では使用できません。このアノテーションは、主に、書き換えられたメソッドが親クラスで定義されたメソッドと一貫性があるかどうかをチェックするようにコンパイラーに指示するために、サブクラスに親クラスのメソッドまたはインターフェース内のメソッドを強制的にオーバーライドさせることができます。オーバーライドされたメソッドのシグネチャに一貫性がない場合は、コンパイル エラーが表示されます。メソッドの署名が矛盾している場合、エラー プロンプトは表示されず、新しいメソッドとして扱われます。このようなメカニズムを通じて、プログラマはいくつかの低レベルのミスを回避できます。
5. 変数の隠蔽
5.1 コンセプト
メンバー変数がサブクラスで定義されており、その変数の名前が親クラスのメンバー変数と同じで、データ型がまったく同じではない可能性がある場合、この変数を hidden と呼びます。つまり、サブクラスのメンバ変数は親クラスから継承したメンバ変数を再定義し、サブクラス変数は親クラスの変数を隠します。したがって、サブクラスがそれ自体で定義されたメソッドを実行する場合、操作のメンバー変数は、親クラスの同じ名前の変数ではなく、それ自体で定義された変数にデフォルト設定されます。非表示のメンバー変数を操作する必要がある場合は、 super キーワードを使用して呼び出すことができます。
次に、ケースを使用して変数の隠蔽の使用法を示します。
5.2 ケースの実装
次の図に示すように、親クラスでメンバー変数名を定義します。
次の図に示すように、同じメンバー変数名がサブクラスでも定義されています。
Son クラスで名前を直接使用する場合は、デフォルトで Son 自身の変数が使用されますが、Father クラスで name 変数を使用したい場合は、「 super.attribute」の形式で使用できます。実行結果は次の図に示されています。
6. メソッドの隠蔽
サブクラスが親クラスを継承する場合、変数の隠蔽現象が発生するため、メソッドの隠蔽現象も発生します。
6.1 コンセプト
メソッドの書き換えはサブクラスが親クラスのオブジェクト メソッドをオーバーライドすることを意味し、メソッドの隠蔽はサブクラスが親クラスの静的メソッド (クラス メソッド)をオーバーライドすることを意味することがわかります。Javaの静的メソッドはサブクラスに継承できますか? 答えは「はい」ですが、サブクラスに親クラスと同じ名前とパラメータを持つメソッドがある場合、親クラスのメソッドは非表示になります。
6.2 ケースの実装
まず、静的メソッド Eat を持つ Father 親クラスを定義します。
/**
* @author 一一哥Sun
* 千锋教育
* 定义父类
*/
public class Father {
// 吃---静态方法
public static void eat() {
System.out.println("爹吃馒头");
}
}
次に、静的メソッド Eat を持つ Son サブクラスを定義します。静的メソッドは継承できることがわかっているため、Son サブクラスが独自の Eat() メソッドを定義していない場合は、Father 親クラスの Eat() メソッドをデフォルトで使用できます。ただし、サブクラスにも Eat() メソッドを定義すると、サブクラス内の同じ名前の静的メソッドによって親クラスの Eat() メソッドが隠蔽されます。これはメソッドの隠蔽です。
/**
* @author 一一哥Sun
* 千锋教育
* 子类继承父类
*/
public class Son extends Father {
// 吃---静态方法
//如果子类中没有定义该方法,则子类可以继承使用父类的eat()方法
public static void eat() {
//子类覆盖父类中的同名静态方法(类)
System.out.println("儿子吃肉");
}
public static void main(String[] args) {
//调用子类自己的静态方法
eat();
//调用父类的静态方法
Father.eat();
}
}
実行結果は次の図に示されています。
6.3 概要
この事例を通じて、次の結論を導き出すことができます。
- サブクラスは親クラスから静的メソッドを継承できます。
- サブクラスは親クラスの静的メソッドをオーバーライドできませんが、オーバーロードすることはできます。
- 親クラスと同じ静的メソッドがサブクラスに定義されている場合、親クラスの同じ名前のメソッドはサブクラスによって隠蔽されます。
2. 書き換えとオーバーロードの違い
Java にはメソッドの書き換え (Override) とメソッドのオーバーロード (Overload) があり、初心者にとっては混乱しやすいです。したがって、多くの面接官は、ジュニア プログラマーを採用する際に、メソッドの書き換えとメソッドのオーバーロードの違いを尋ねたがります。
実際、メソッドの書き換えである Override とメソッドのオーバーロードである Overload の最大の違いは、メソッドのシグネチャの違いにあります。同じクラス内の複数のメソッドが異なるシグネチャを持つ場合、それはメソッドのオーバーロードであり、オーバーロードされたメソッドは新しいメソッドです。親クラスと子クラス間の複数のメソッド シグネチャが同じで、戻り値も同じ場合、メソッド オーバーライド Override になります。
もちろん、書き換えとオーバーロードの違いをより詳しく説明したい場合は、次の章を参照してください。
1. 過負荷の特徴
- メソッドのオーバーロードには、名前は同じだがパラメーター (パラメーターの型、番号、順序) が異なるメソッドが必要です。
- オーバーロードされたメソッドは戻り値やアクセス修飾子とは何の関係もありません。
- オーバーロードされたメソッドは同じクラス内で発生します。つまり、クラス内に同じ名前の複数のメソッドが作成されます。
2. リライトの特徴
- オーバーライドされたメソッドは親子クラスで発生し、継承関係が必要です。
- 親クラスのメンバー メソッドは、そのサブクラスによってのみ書き換えることができます。つまり、メソッドを継承できない場合、このメソッドを書き換えることはできません。
- Final によって変更されたメソッドはオーバーライドできません。
- static によって変更されたメソッドはオーバーライドできませんが、再度宣言することはできます。
- コンストラクターをオーバーライドすることはできません。
- サブクラスと親クラスが同じパッケージ内にある場合、サブクラスは、private および Final によって変更されたメソッドを除く、親クラスのすべてのメソッドをオーバーライドできます。
- サブクラスと親クラスが同じパッケージ内にない場合、サブクラスは public および protected によって変更された親クラスの非finalメソッドのみを書き換えることができます。
- @Override アノテーションは、メソッドが書き換えられるときに使用できます。
- メソッドのシグネチャは同じである必要があります。
- 戻り値の型は同じです。
- アクセス修飾子はより一般的です。
- 宣言された例外タイプは一貫している必要があります。
-------------------------------------------------- ----長編映画は終わりました、ここからは余談です------------------------ ------- ---------
3. 結論
メソッドのオーバーライドとは何なのか理解できましたか? また、メソッドのオーバーロードとメソッドの書き換えの違いは、若手プログラマーにインタビューするときによく聞かれる質問であり、全員がそれをしっかりと把握する必要があります。メソッド書き換えの基礎ができたので、次はポリモーフィズムについて学習します。次の記事をお楽しみに。
また、一人で勉強するのが難しい場合は、Yi Geの学習互助会に参加して、みんなで交流して一緒に学ぶこともできます。
4. サポートビデオ
技術記事を読むことに慣れていない場合、または記事内の技術概念がよく理解できない場合は、 Yigeが選んだビデオ チュートリアルをご覧ください。この記事に付属する Java 学習ビデオは次のリンクにあります。
5. 今日の宿題
1. 最初の質問
サブクラスが親クラスの機能を超えるように、親クラスとサブクラスを設計します。