やあ!あなたはすでに Java メソッドを使用しており、それについてよく知っています。メソッドのオーバーライドの仕組み - 1同じ名前で引数リストが異なる多数のメソッドを持つクラスに遭遇したことがあるはずです。このような場合にはメソッドのオーバーロードを使用したことを思い出してください。今日は別の状況を見てみましょう。共通のメソッドが 1 つありますが、呼び出されるクラスに応じて異なる動作を行う必要があると想像してください。この動作はどのように実装すればよいでしょうか。これを理解するために、動物を表す親クラスを取得しAnimalspeakその中にメソッドを作成してみましょう。

public class Animal {
  
   public void speak() {

       System.out.println("Hello!");
   }
}
私たちはプログラムを書き始めたばかりですが、おそらく潜在的な問題が見えてくるでしょう。世界にはたくさんの動物がいて、それらはすべて異なる「話し方」をします。猫がニャーと鳴き、アヒルが鳴き声を上げ、ヘビがシューシューと鳴くなどです。私たちの目標は単純ですメソッドのオーバーライドの仕組み - 2。話すためのメソッドを大量に作成することは避けたいと考えています。meow()鳴き声やシューシューという鳴き声などのメソッドを作成する代わりに、メソッドが呼び出されたhiss()ときにヘビがシューシューと鳴き、猫がニャーと鳴き、犬が吠えるようにしたいと考えています。これは、メソッドのオーバーライドをspeak()使用して簡単に実現できます。Wikipedia ではこの用語について次のように説明しています。メソッドのオーバーライドは、オブジェクト指向プログラミングにおいて、スーパークラスまたは親クラスの 1 つによってすでに提供されているメソッドの特定の実装をサブクラスまたは子クラスが提供できるようにする言語機能です。それは基本的に正しいです。オーバーライドを使用すると、親クラスのメソッドを取得し、各派生クラスに独自の実装を作成できます。子クラスの新しい実装は、親クラスの実装を「置き換え」ます。これがどのようになるかを例で見てみましょう。クラスの 4 つの子孫を作成しましょうAnimal

public class Bear extends Animal {
   @Override
   public void speak() {
       System.out.println("Growl!");
   }
}
public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}


public class Snake extends Animal {

   @Override
   public void speak() {
       System.out.println("Hiss!");
   }
}
これは将来のための小さなライフハックです。親クラスのメソッドをオーバーライドするには、 IntelliJ IDE で派生クラスのコードに移動し、Ctrl+Oを押して、メニューから [メソッドのオーバーライド...]を選択します。最初からホットキーの使用に慣れてください。コーディングがスピードアップします。望ましい動作を得るために、いくつかのことを行いました。
  1. 各子孫クラスで、親クラスのメソッドと同じ名前のメソッドを作成しました。
  2. メソッドに親クラスと同じ名前を付けるだけではなく、その動作をオーバーライドしたいことをコンパイラーに伝えました。コンパイラへのこの「メッセージ」は、@Overrideアノテーションを介して伝えられます。
    メソッドの上にある @Override アノテーションは、コンパイラー (およびコードを読んでいる他のプログラマー) に、「心配しないでください。これは間違いや見落としではありません。このメソッドが既に存在することは認識しているので、それをオーバーライドしたいと考えています」と伝えます。 。

  3. 各子孫クラスに必要な実装を作成しました。このspeak()メソッドが呼び出されるとき、ヘビはシューシューという音を立て、クマはうなり声を上げます。
これがプログラムでどのように機能するかを見てみましょう。

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.speak();
       animal2.speak();
       animal3.speak();
       animal4.speak();
   }
}
コンソール出力:

Woof! 
Meow! 
Growl! 
Hiss!
素晴らしいです。すべてが正常に機能します。型が親クラスである 4 つの参照変数を作成しAnimal、それらに子孫クラスの 4 つの異なるオブジェクトを割り当てました。その結果、各オブジェクトは異なる動作をします。各派生クラスでは、オーバーライドされたメソッドがクラスのspeak()既存のメソッド(コンソールに「Speaking:」と表示されるだけ) を置き換えます。メソッドのオーバーライドにはいくつかの制限があります。 speak()Animalメソッドのオーバーライドの仕組み - 3
  1. オーバーライドされたメソッドには、親クラスのメソッドと同じ引数が必要です。

    speak親クラスのメソッドが を入力として受け取る場合String、子孫クラスのオーバーライドされたメソッドも をString入力として受け取る必要があります。それ以外の場合、コンパイラはエラーを生成します。

    
    public class Animal {
    
       public void speak(String s) {
    
           System.out.println("Speaking: " + s);
       }
    }
    
    public class Cat extends Animal {
    
       @Override // Error!
       public void speak() {
           System.out.println("Meow!");
       }
    }
    

  2. オーバーライドされたメソッドの戻り値の型は、親クラスのメソッドと同じである必要があります。

    そうしないと、コンパイル エラーが発生します。

    
    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    
    public class Cat extends Animal {
    
       @Override
       public String speak() {         // Error!
           System.out.println("Meow!");
           return "Meow!";
       }
    }
    

  3. オーバーライドされたメソッドのアクセス修飾子も、元のアクセス修飾子と異なるものにすることはできません。

    
    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    public class Cat extends Animal {
    
       @Override
       private void speak() {      // Error!
           System.out.println("Meow!");
       }
    }
    
Java では、メソッドのオーバーライドはポリモーフィズムを実装する 1 つの方法です。つまり、その主な利点は、先ほど説明した柔軟性にあるということです。シンプルで論理的なクラスの階層を構築できます。各クラスには特定の動作 (犬の吠え、猫の鳴き声) がありますが、インターフェイスは 1 つだけです。さまざまなメソッド (たとえば、、 など)speak()の束ではなく、全員に単一のメソッドを提供します。bark()meow()