Javaのfinal

Javaのfinal修飾子はクラスを継承できなくしたり、メソッドをオーバーライドできなくしたり、変数の値を変更できない定数化したりできます。この記事では、final修飾子の使い方をサンプルを交えてご紹介します。

finalクラス

final修飾子を指定してクラスを宣言すると、そのクラスはサブクラスで継承できなくなります

final class Example {
  // サブクラスで継承不可
}

finalメソッド

final修飾子を指定してメソッドを宣言すると、そのメソッドはサブクラスでオーバーライドできなくなります

class Example {
  final void example() {
    // サブクラスでオーバーライド不可
  }
}

フィールド変数

フィールド変数の定義にfinal修飾子を付けると、そのフィールド変数に値を代入した後に、その値を変更できなくなる。つまり、定数として扱われる。

final修飾子を付けたフィールド変数には、値を一度しか代入できない。次に示すいずれかの方法でフィールド変数に値を代入する。

final修飾子を付けたフィールド変数を定義するときに、初期値を指定する例を次に示す。

public class Example {
  // 値の変更不可
  final String s = "example";

  public static void main(String[] args) {
    // 下記の操作はできない
    // s = "new";
    // s = new String();
  }
}

クラスのコンストラクタは、クラスのインスタンスを生成するときに一度だけ呼ばれる。このときにfinal修飾子を付けたフィールド変数に値を代入する。

public class Example {
  final String s;

  public Example() {
    s = "example";
  }
}

引数があるコンストラクタを定義しておけば、インスタンスを生成するときに初期値を指定できる。

public class Example {
  final String s;

  public Example() {
    s = "example";
  }

  public Example(String init) {
    s = init;
  }
}

ローカル変数

ローカル変数の定義にfinal修飾子を付けると、そのローカル変数に値を代入した後に、その値を変更できなくなる。つまり、定数として扱われる。

public class Example {
  public static void main(String[] args) {
    // 値の変更不可
    final String s = "example";

    // 下記の操作はできない
    // s = "new";
    // s = new String();
  }
}

メソッドの引数

メソッドの引数にfinal修飾子をつけると、その引数の内容を変更することができなくなる。final修飾子を付けた引数を変更するソースプログラムは、コンパイル時にエラーとなる。

public class Example {
  public static void main(String[] args) {
    String s = "example";
    foo(s);
  }
  static void foo(final String s) {
    System.out.println(s);
    // 下記の操作はできない
    // s = "new";
    // s = new String();
  }
}

抽象クラス

抽象クラスにfinal修飾子を付けることはできない。抽象クラスはサブクラスによって継承されることを前提としているが、final修飾子はそれを禁止するため、矛盾するからである。

抽象クラスで宣言する抽象メソッドにfinal修飾子を付けることはできない。抽象クラスで宣言する抽象メソッドは継承クラスで実装することを前提としているが、final修飾子はそれを禁止するため、矛盾するからである。

abstract class AbstractEmp {
  int getEmpNo();
  void setEmpNo(int empno);
}

インタフェース

インタフェースにfinal修飾子を付けることはできない。インタフェースはサブクラスによって継承(実装)されることを前提としているが、final修飾子はそれを禁止するため、矛盾するからである。

インタフェースで宣言するメソッドにfinal修飾子を付けることはできない。インタフェースで宣言するメソッドは実装クラスで実装することを前提としているが、final修飾子はそれを禁止するため、矛盾するからである。

interface EmpInterface {
  int getEmpNo();
  void setEmpNo(int empno);
}

参考文献

Oracle 2021. Writing Final Classes and Method. The Java™ Tutorials