Java
 Computer >> コンピューター >  >> プログラミング >> Java

Javaでメソッドのオーバーライドを防ぐ3つの方法を徹底解説

Javaにおけるメソッドのオーバーライドは、実行時に行われるメソッドの動的バインディング(ダイナミックバインディング)によって実現されています。つまり、特定のメソッドに対してコンパイラに静的バインディング(スタティックバインディング)を強制させることができれば、そのメソッドが派生クラスでオーバーライドされるのを防ぐことが可能です。

Javaでメソッドのオーバーライドを防ぐ方法は、主に以下の3つがあります。

  • 基底クラスのメソッドを final にする
  • 基底クラスのメソッドを static にする
  • 基底クラスのメソッドを private にする

1. finalメソッドはオーバーライドできない

メソッドに final を付けることで、「このメソッドは派生クラスでオーバーライド禁止」という制約を明示的に課すことができます。これは、クラス設計上「この処理は変更されたくない」という意図を表す最も一般的な方法です。

サンプルコード

class Base {
    public void show() {
        System.out.println("Base class show() method");
    }
    public final void test() {
        System.out.println("Base class test() method");
    }
}
class Derived extends Base {
    public void show() {
        System.out.println("Derived class show() method");
    }
    // test() は Base クラスで final 宣言されているためオーバーライド不可
    /*
     * public void test() { System.out.println("Derived class test() method"); }
     */
}
public class Test {
    public static void main(String[] args) {
        Base ref = new Derived();
        // final メソッド test() の呼び出し
        ref.test();
        // オーバーライドされたメソッド show() の呼び出し
        ref.show();
    }
}

実行結果

Base class test() method
Derived class show() method

このように、final ではない show() は派生クラスの実装が呼び出される一方、final である test() は常に基底クラスの実装が使われます。

2. staticメソッドはオーバーライドできない

staticメソッドはクラスそのものに紐づいており、個々のオブジェクトには紐づきません。JVMは非staticメソッドを呼び出す際に this 参照を渡しますが、staticメソッドの場合はこれを行いません。そのため、staticメソッドには実行時バインディングが適用されず、オーバーライドが成立しません。

なお、派生クラスで基底クラスと同じシグネチャのstaticメソッドを定義した場合、それはオーバーライドではなくメソッドの隠蔽(メソッドハイディング)として扱われます。

サンプルコード

class Base {
    public void show() {
        System.out.println("Base class show() method");
    }
    public static void test() {
        System.out.println("Base class test() method");
    }
}
class Derived extends Base {
    public void show() {
        System.out.println("Derived class show() method");
    }
    // これはオーバーライドではなく、Derived クラスの新しいメソッドとして扱われる
    public static void test() {
        System.out.println("Derived class test() method");
    }
}
public class Test {
    public static void main(String[] args) {
        Base ref = new Derived();
        // 静的バインディングのため、参照型 Base の test() が呼ばれる
        ref.test();
        // オーバーライドされたメソッド show() の呼び出し
        ref.show();
    }
}

実行結果

Base class test() method
Derived class show() method

変数 ref の実際のインスタンスは Derived ですが、staticメソッドは参照変数の型(ここでは Base)に基づいてコンパイル時に結び付けられるため、基底クラスの test() が呼び出されます。

3. privateメソッドはオーバーライドできない

基底クラスのprivateメソッドは、そもそも派生クラスから見えません。可視性がない以上、オーバーライドの対象になり得ません。派生クラスで同じ名前・シグネチャのメソッドを定義しても、それはオーバーライドではなく、まったく別の新しいメソッドとして扱われます。

サンプルコード

class Base {
    public void show() {
        System.out.println("Base class show() method");
    }
    private void test() {
        System.out.println("Base class test() method");
    }
}
class Derived extends Base {
    public void show() {
        System.out.println("Derived class show() method");
    }
    // これはオーバーライドではなく、別の独立したメソッドとして扱われる
    public void test() {
        System.out.println("Derived class test() method");
    }
}
public class Test {
    public static void main(String[] args) {
        Base ref = new Derived();
        // privateメソッド test() は外部から呼び出せないため、この行はコンパイルエラーになる
        // ref.test();
        // オーバーライドされたメソッド show() の呼び出し
        ref.show();
    }
}

実行結果

Derived class show() method

まとめ

方法仕組み
finalメソッドオーバーライドを明示的に禁止する
staticメソッド静的バインディングのため実行時の多態性が働かない
privateメソッド派生クラスから見えないためオーバーライド対象にならない

「継承先での挙動変更を許したくない」場合は final を使うのが基本です。staticやprivateは言語仕様の結果としてオーバーライドが起こらないだけであり、意図的な設計手段としては final が最も適切です。用途に応じて使い分けましょう。

  1. Java HashMapクラスの使い方を徹底解説!基本操作から実践例まで

    プログラミングにおいて、データ型は特定の種類のデータを分類するために使用されます。データ型ごとに保存方法が異なり、値がどのデータ型で保存されるかによって、その値に対して実行できる操作が決まります。 Javaで開発を行う際によく使われるクラスのひとつが、JavaのHashMapクラスです。このクラスはコレクションフレームワークの一部であり、Mapデータ型を使ってデータを保存することを可能にします。 この記事では、Java HashMapの基礎知識、HashMapの作成方法、そしてHashMapクラスを扱う際に使用できる主なメソッドについて解説します。記事全体を通してサンプルコードを交えながら、H

  2. Javaのデフォルトメソッドを使ってダイヤモンド問題を解決する方法

    継承(Inheritance)とは 継承とは、あるクラスが別のクラスの性質(プロパティやメソッド)を受け継ぐ、2つのクラス間の関係のことです。この関係は extends キーワードを使って次のように定義します。 public class A extends B{ } 性質を受け継ぐ側のクラスは「サブクラス(子クラス)」、受け継がれる側のクラスは「スーパークラス(親クラス)」と呼ばれます。 継承が行われると、スーパークラスのメンバーのコピーがサブクラスのオブジェクト内に作成されます。そのため、サブクラスのオブジェクトを使えば、親クラスと子クラスの両方のメンバーにアクセスすることが可能です。 多重