こんにちは!あなたはすでに Java のメソッドを使用しており、それについてよく知っています。おそらく、同じ名前で引数が異なるメソッドが 1 つのクラスに多数あるという状況に遭遇したことがあるでしょう。覚えていると思いますが、そのような場合にはメソッドのオーバーロード メカニズムを使用しました。今日は別の状況を見てみましょう。共通のメソッドが 1 つありますが、呼び出されたクラスに応じて異なることを行う必要があると想像してください。この動作を実装するにはどうすればよいでしょうか? それを理解するために、
Animal
動物を表す親クラスを取得し、その中にメソッドvoice
「voice」を作成しましょう。
public class Animal {
public void voice() {
System.out.println("Voice!");
}
}
私たちはプログラムを書き始めたばかりですが、おそらく潜在的な問題がわかるでしょう。世界にはたくさんの動物がいますが、それらはすべて異なる「話し方」をします。猫はニャーと鳴き、アヒルは鳴き声を上げ、ヘビはシューシューと鳴きます。 私たちの目標はシンプルです。投票するためのメソッドを大量に作成しないようにすることです。voiceCat()
鳴き声やシューシューという鳴き声などのメソッドを作成する代わりに、メソッドが呼び出されたときにヘビがシューシューと鳴き、猫がニャーと鳴き、犬が吠えるようにしたいとvoiceSnake()
考えています。これは、メソッド オーバーライド メカニズム (Java のオーバーライド)voice()
を使用して簡単に実現できます。Wikipedia では、「オーバーライド」という用語について次のように説明しています。 オブジェクト指向プログラミングにおけるメソッドのオーバーライドは、サブクラスまたは子クラスがスーパークラスの 1 つにすでに実装されているメソッドの特定の実装を提供できるようにするプログラミング言語の機能の 1 つです。または親クラス。一般的にはそれは正しいです。オーバーライドすると、親クラスのメソッドを取得し、各子孫クラスでこのメソッドの独自の実装を作成できます。新しい実装は、子クラスの親を「置き換え」ます。これがどのようなものかを例で見てみましょう。私たちのクラスの 4 つの後継クラスを作成しましょう。 Animal
public class Bear extends Animal {
@Override
public void voice() {
System.out.println("Р-р-р!");
}
}
public class Cat extends Animal {
@Override
public void voice() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
@Override
public void voice() {
System.out.println("Woof!");
}
}
public class Snake extends Animal {
@Override
public void voice() {
System.out.println("Ш-ш-ш!");
}
}
将来のための小さなライフハック: 親クラスのメソッドをオーバーライドするには、 Intellij IDE a で子孫クラスのコードに移動し、 Ctrl+Oを押して、メニューから「メソッドのオーバーライド... 」を選択します。最初からホットキーの使い方に慣れておくと、プログラムを書くスピードが速くなります。必要な動作を設定するために、いくつかのことを行いました。
- 各子孫クラスに、親クラスのメソッドと同じ名前のメソッドを作成しました。
-
メソッドに親クラスと同じ名前を付けたのには、その動作をオーバーライドするためという理由があることをコンパイラーに伝えました。コンパイラへのこの「メッセージ」のために、メソッドに@Override アノテーションを付けます。
メソッドの上に配置された @Override アノテーションは、コンパイラー (そしてコードを読んでいるプログラマー) に次のように伝えます。そのようなメソッドがすでに存在していることを思い出したので、それをオーバーライドしたいと思います。」 - 各子孫クラスに必要な実装を作成しました。呼ばれると、ヘビは
voice()
シューシューと鳴き、クマはうなり声を上げます。
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Bear();
Animal animal4 = new Snake();
animal1.voice();
animal2.voice();
animal3.voice();
animal4.voice();
}
}
コンソール出力: すごい! ニャー!うーん!しー! 素晴らしいです。すべてが正常に機能します。親クラスの 4 つの参照変数を作成しAnimal
、それらを子孫クラスの 4 つの異なるオブジェクトに割り当てました。その結果、各オブジェクトは異なる動作をします。各子孫クラスでは、オーバーライドされたメソッドがクラスのvoice()
「ネイティブ」メソッド(単に「Voice!」をコンソールに出力する) を置き換えました。 オーバーライドにはいくつかの制限があります。 voice()
Animal
-
オーバーライドされたメソッドには、親メソッドと同じ引数が必要です。
voice
親クラスのメソッドが input として受け入れる場合String
、子クラスのオーバーライドされたメソッドも input として受け入れる必要がありますString
。そうでない場合、コンパイラはエラーをスローします。public class Animal { public void voice(String s) { System.out.println("Voice! " + s); } } public class Cat extends Animal { @Override//error! public void voice() { System.out.println("Meow!"); } }
-
オーバーライドされたメソッドの戻り値の型は、親メソッドと同じである必要があります。
そうしないと、コンパイル エラーが発生します。
public class Animal { public void voice() { System.out.println("Voice!"); } } public class Cat extends Animal { @Override public String voice() { //error! System.out.println("Meow!"); return "Meow!"; } }
-
オーバーライドされたメソッドのアクセス修飾子も、「元の」アクセス修飾子と異なるものにすることはできません。
public class Animal { public void voice() { System.out.println("Voice!"); } } public class Cat extends Animal { @Override private void voice() { //error! System.out.println("Meow!"); } }
voice()
多数のメソッドではなくすべてに対して1 つのメソッド) を使用しますvoiceDog()
。voiceCat()
GO TO FULL VERSION