Java超|finalの使い方と役割

自由に継承できること、自由に上書きできること、自由に値を変えられること。
それらをあえて止めるのが final の役割です。final を使うと、「ここは変えてはいけない」という設計者の意図を、Javaのコードにはっきり刻めます。

これまでJavaのオブジェクト指向では、継承によってクラスを広げたり、オーバーライドによって親クラスのメソッドを子クラス向けに作り直したりできることを学んできました。

継承やオーバーライドは、とても便利です。

親クラスに共通部分をまとめ、子クラスで個性を追加できます。
同じ show() というメソッドでも、普通のサイヤ人戦士なら普通の表示、スーパーサイヤ人戦士なら変身段階まで含めた表示にできます。

ドラゴンボールの世界観でたとえると、SaiyanWarrior というサイヤ人戦士の共通の土台があり、そこから SuperSaiyanWarrior のような特別な戦士を作るイメージです。

さらに、スーパーサイヤ人戦士ごとに表示内容や技の出し方を変えたい場合は、オーバーライドで自分流に作り直せます。

ただし、設計では「自由に変えられること」だけが正解ではありません。

中には、次のようなものもあります。

守りたいもの
子クラスで勝手に変えてほしくない処理戦士認証の手順、任務規則の確認
これ以上継承させたくない完成済みのクラス最終奥義を持つ完成形の戦士クラス
書き換えられてはいけない値最大戦士数、任務レベル、組織名、固定された基準値

このような「ここは変えないでほしい」という設計上の意図を表すために使うのが final です。

final は、単に厳しく制限するためのものではありません。

変えてよい場所と、変えてはいけない場所をはっきり分けるための修飾子です。

ドラゴンボール風に言えば、戦士ごとの技の個性は自由に伸ばしてよいけれど、戦士管理本部の絶対規則や完成済みの奥義、固定された基準値は勝手に変えてはいけない、ということです。

この記事では、final をメソッド、クラス、フィールドに付けたときの違いを、サイヤ人戦士の設計に置き換えて整理します。特に、final メソッドはオーバーライドを止める、final クラスは継承を止める、final フィールドは値の再代入を止める、という3つの役割を中心に解説します。

final は「それ以上変更させない」を表す

final の基本イメージは、とてもシンプルです。

「それ以上変更させない」

これが final の中心にある意味です。

ただし、final をどこに付けるかによって、何を変更できなくするのかが変わります。

final を付ける場所変更できなくなるもの意味
メソッドオーバーライド子クラスで上書きできない
クラス継承サブクラスを作れない
フィールド値の再代入値を変更できない

ドラゴンボール風にたとえると、次のように考えると分かりやすいです。

final の対象ドラゴンボール風のイメージ
final メソッドこの技の型は変えてはいけない
final クラスこの戦士の型は完成形なので派生させない
final フィールドこの数値は戦士管理本部の絶対ルールなので書き換えない

同じ final でも、付ける場所によって役割が変わります。

そのため、final を見たときは、まず「何を固定しているのか」を確認することが大切です。

final を見るときの基本の読み方

final が出てきたら、次のように読み取ると整理しやすくなります。

コードの例読み取り方
public final void confirmRule()このメソッドは子クラスでオーバーライドできない
final class UltimateWarriorこのクラスは継承できない
static final int MAX_WARRIOR_COUNT = 12この値は変更できない定数

final は1つの単語ですが、止めているものが違います。

メソッドなら、子クラスによる作り直しを止めます。
クラスなら、サブクラス化を止めます。
フィールドなら、値の再代入を止めます。

このように「final は何を止めているのか」を見ることが、最初のポイントです。

図:final の3つの使い方

この図が示していること

この図では、final の3つの使い方を並べて整理しています。

左側は final メソッドです。

メソッドに final を付けると、子クラスでオーバーライドできなくなります。

中央は final クラスです。

クラスに final を付けると、そのクラスを継承できなくなります。

右側は final フィールドです。

フィールドに final を付けると、その値をあとから変更できなくなります。

この図から分かるのは、final の共通イメージは「それ以上変更させない」ですが、何を止めるのかは付ける場所によって変わるということです。

メソッドに final を付ける意味

まずは、メソッドに付ける final です。

メソッドに final を付けると、そのメソッドはサブクラスでオーバーライドできなくなります。

たとえば、SaiyanWarrior クラスに confirmRule() というメソッドがあるとします。

class SaiyanWarrior
{
    public final void confirmRule()
    {
        System.out.println("サイヤ人戦士は任務規則を守ります。");
    }
}

このように public final void confirmRule() と書くと、サブクラスで同じ confirmRule() を定義して上書きすることはできません。

class SuperSaiyanWarrior extends SaiyanWarrior
{
    // これはできない
    public void confirmRule()
    {
        System.out.println("スーパーサイヤ人専用の規則に変えます。");
    }
}

このように書こうとするとエラーになります。

なぜなら、親クラス側で final を付けているため、confirmRule() は「子クラスで変更してはいけないメソッド」として固定されているからです。

なぜメソッドをオーバーライド禁止にするのか

オーバーライドは便利です。

子クラスごとに、ふさわしい動きへ作り直せるからです。

しかし、すべてのメソッドを自由にオーバーライドできると困る場合があります。

たとえば、次のような処理です。

変えられると困る処理理由
認証処理勝手に変えられると安全性が崩れる
共通ルール表示子クラスごとに違う内容になると統一性がなくなる
重要な手順処理順序が変わると不具合の原因になる
基本契約の処理クラス全体の意味が崩れる

ドラゴンボール風にたとえると、サイヤ人戦士には全員が守るべき共通の任務規則があります。

たとえば、次のような処理です。

共通規則内容
身元確認正式な戦士であることを確認する
任務確認担当任務を確認する
規則遵守戦士管理本部の決まりを守る

このような処理を子クラス側で勝手に変えられると、戦士管理本部全体のルールが崩れてしまいます。

そのため、親クラスのメソッドに final を付けて、「この振る舞いは共通ルールとして固定します」と宣言します。

メソッド final の見方

メソッドに final が付いているときは、次のように読み取ります。

書き方読み取り方
public final void confirmRule()このメソッドは子クラスでオーバーライドできない
final がないメソッド条件を満たせばオーバーライドできる

つまり、メソッド final は、子クラスの自由をすべて否定するものではありません。

変えてよいメソッドと、変えてはいけないメソッドを分けるための指定です。

メソッドの種類final を付けるか
子クラスごとに動きを変えてよいもの付けない
全クラスで同じ動きを守らせたいもの付ける

ドラゴンボール風にたとえると、戦士ごとの気弾の出し方や戦闘スタイルは変えてよくても、戦士認証や本部規則の確認は変えてはいけない、ということです。

クラスに final を付ける意味

次に、クラスに付ける final です。

クラスに final を付けると、そのクラスは継承できなくなります。

つまり、そのクラスを親クラスにしてサブクラスを作ることができません。

たとえば、次のように書きます。

final class UltimateWarriorStyle
{
    public void showStyle()
    {
        System.out.println("完成された究極戦士の型です。");
    }
}

この UltimateWarriorStyle クラスは final class なので、次のように継承できません。

// これはできない
class CustomWarriorStyle extends UltimateWarriorStyle
{
}

final class は、「このクラスはここで完成形なので、これ以上派生させません」という意味を持ちます。

なぜクラスを継承禁止にするのか

継承は強力です。

既存のクラスを土台にして、新しいクラスを作れるからです。

しかし、すべてのクラスを自由に継承できるようにしておくと、設計が崩れることがあります。

たとえば、次のようなクラスです。

継承させたくないクラス理由
完成済みのクラスこれ以上機能を変えられたくない
内部ルールが厳密なクラス派生によって安全性が崩れる可能性がある
使い方を固定したいクラス想定外のサブクラスを防ぎたい
不変性を守りたいクラス子クラスで状態管理を変えられたくない

ドラゴンボール風にたとえると、ある最終奥義が「これ以上変化させてはいけない完成形」として定められているようなものです。

もし、その型を自由に派生できるようにしてしまうと、元の意味やルールが崩れるかもしれません。

そのため、クラスに final を付けて、次のように宣言します。

この型はここで完成です。
これ以上、派生形は作らせません。

これが final class の役割です。

クラス final の役割を整理する

クラスに final を付ける場面を整理すると、次のようになります。

こんなときfinal を付ける意味
そのクラスを完成形として扱いたい継承を禁止する
派生されると設計が崩れるサブクラス作成を防ぐ
使い方を厳密に固定したい型の広がりを止める
想定外のオーバーライドを防ぎたい子クラスを作らせない

継承は拡張性を生みます。

一方で、final class は拡張性よりも安定性を優先します。

考え方意味
継承を許す将来の拡張を考える
final class にする完成形として固定する

ドラゴンボール風にたとえると、まだ成長や派生を許す戦士の型もあれば、完成された奥義として固定する型もある、ということです。

フィールドに final を付ける意味

最後に、フィールドに付ける final です。

フィールドに final を付けると、その値は一度設定したあと変更できなくなります。

これは、途中で書き換えてはいけない値を表すときに使います。

たとえば、戦士管理本部の最大登録戦士数を固定したい場合、次のように書けます。

static final int MAX_WARRIOR_COUNT = 12;

この MAX_WARRIOR_COUNT は final なので、あとから別の値を代入できません。

// これはできない
MAX_WARRIOR_COUNT = 20;

final フィールドは、「この値は固定です」という意味をコードに表します。

フィールド final はなぜ大切か

プログラムの中には、変わってよい値と、変わってはいけない値があります。

ドラゴンボール風にたとえると、戦士の現在地や体力は状況によって変わります。

しかし、戦士管理本部の最大登録戦士数や、任務の基本レベル、組織名のような値は、勝手に変わってはいけません。

値の種類変わるか
戦士の現在地変わる
戦士の体力変わる
任務中の状態変わる
最大登録戦士数変わらない
基本任務レベル変わらない
組織名変わらない

もし、変わってはいけない値が途中で書き換えられると、次のような問題が起こります。

問題内容
前提が崩れるルールが途中で変わってしまう
処理結果が不安定になる同じ処理でも結果が変わる可能性がある
バグの原因になるどこで値が変わったのか追いにくい
設計意図が伝わりにくい固定値なのか状態値なのか分からない

final を付けておけば、「この値は変更しないものだ」と明確になります。

フィールド final は定数につながる

final フィールドは、定数としてよく使われます。

特に、次の形はよく出てきます。

static final int MAX_WARRIOR_COUNT = 12;

ここでは static と final を組み合わせています。

修飾子役割
staticクラス全体で共有する
final値を変更できなくする

つまり static final は、「クラス全体で共通して使う、変更できない値」を表します。

ドラゴンボール風にたとえると、特定の戦士だけが持つ値ではなく、戦士管理本部全体で共有する決まりの数です。

たとえば、次のような定数が考えられます。

static final int MAX_WARRIOR_COUNT = 12;
static final int DEFAULT_MISSION_LEVEL = 1;
static final String ORGANIZATION_NAME = "サイヤ人戦士管理本部";

このような値は、宣言時に初期化しておくのが基本です。

final はあとから値を変えられないため、最初に何の値にするかを決めておく必要があります。

final とオーバーライドの関係

final は、オーバーライドと深く関係します。

オーバーライドは、親クラスのメソッドを子クラスで自分向けに作り直す仕組みでした。

これはとても便利です。

しかし、すべてのメソッドを自由に作り直せると、親クラスが守りたい共通ルールまで変えられてしまう可能性があります。

そこで、設計では次のように使い分けます。

メソッドの種類どうするか
子クラスごとに変えてよいもの通常どおりオーバーライド可能にする
親クラスのルールとして固定したいものfinal を付ける

ドラゴンボール風にたとえると、戦士ごとの戦い方は違ってよいです。

亀仙流、鶴仙流、神流、惑星戦士流のように、戦士ごとに個性があります。

一方で、戦士認証や任務規則の確認のような処理は、勝手に変えられると困ります。

つまり final は、オーバーライドを否定するものではありません。

オーバーライドを許す場所と、許さない場所を分けるための道具です。

図:final と継承・オーバーライドの境界線

この図が示していること

この図では、final が継承やオーバーライドの中でどのように境界線を作るかを表しています。

SaiyanWarrior クラスには、attack() と final confirmRule() があります。

attack() には final が付いていないので、SuperSaiyanWarrior クラスでオーバーライドできます。

一方、confirmRule() には final が付いているので、SuperSaiyanWarrior クラスでオーバーライドできません。

また、static final int MAX_RULE_LEVEL は値が固定されているため、あとから変更できません。

この図から分かることは、final が「何も広げさせないためのもの」ではなく、自由に変えてよい部分と、守るべき固定部分を分けるためのものだということです。

final と継承の関係

クラスに final を付けると、継承できなくなります。

これは、継承が悪いからではありません。

継承させないこと自体が、設計として正しい場合があるからです。

継承を許すと、次のようなメリットがあります。

継承を許すメリット内容
クラスを拡張できる新しいサブクラスを作れる
共通部分を再利用できる親クラスの機能を使える
多態性につなげられるスーパークラス型でまとめて扱える

一方で、継承を許すと次のようなリスクもあります。

継承を許すリスク内容
想定外のサブクラスが作られる設計者が想定していない使い方をされる
ルールが崩れる子クラスで不自然な実装がされる可能性がある
管理が複雑になる派生クラスが増えすぎる
一貫性が失われるクラス本来の意味が薄れる

final class は、この広がりを意図的に止めるための仕組みです。

ドラゴンボール風にたとえると、「この戦士の型は完成形なので、これ以上派生させない」と決めるようなものです。

final と値の制御の関係

フィールドに final を付けると、値を変更できなくなります。

これは、オブジェクト指向における状態管理とも関係します。

クラスのフィールドには、状態を表すものがあります。

その中には、変わるべき値と、変わってはいけない値があります。

ドラゴンボール風に考えると、次のようになります。

フィールド変わるか理由
hp変わる戦闘で増減する
currentArea変わる任務で移動する
battleRank変わる場合がある昇格する可能性がある
MAX_WARRIOR_COUNT変わらない戦士管理本部の決まりとして固定
ORGANIZATION_NAME変わらない組織名として固定

このように、変わってよいものと、変わってはいけないものを分けると、コードの意味がはっきりします。

final フィールドは、「この値は状態ではなくルールです」と伝えるための表現でもあります。

final をどう読み取ればよいか

final が出てきたら、まず「何が止められているのか」を見ます。

final の対象止めているもの読み取り方
メソッドオーバーライドこの振る舞いは固定
クラス継承この型は完成形
フィールド値の変更この値は固定

たとえば、次のコードを見たとします。

public final void confirmRule()

これは、confirmRule() が子クラスでオーバーライドできないという意味です。

次のコードならどうでしょうか。

final class UltimateWarriorStyle

これは、UltimateWarriorStyle を継承できないという意味です。

次のコードなら、値が変更できません。

static final int MAX_WARRIOR_COUNT = 12;

このように、final は1つの単語ですが、見る場所によって意味が変わります。

計算ルールや固定値で考える final の活用イメージ

final の考え方は、数学やルールを扱うクラスを考えると理解しやすくなります。

たとえば、計算ルールを扱うクラスでは、勝手に継承されて動きを変えられると困ることがあります。

また、円周率のような値は途中で書き換えられてはいけません。

こうした場面では、final の考え方がとても自然です。

ドラゴンボール風にたとえると、これは個々の戦士が勝手に変えてよい技ではなく、世界の法則や戦士管理本部全体の規則に近いものです。

固定したいものfinal の使い方
勝手に変えてほしくない計算処理final メソッド
継承させたくない計算クラスfinal クラス
書き換えてはいけない値final フィールド

final は、柔軟性を減らすためだけに使うものではありません。

変えてはいけないものを明確に守るために使う、と考えると役割が分かりやすくなります。

図:final は設計を安定させるためのロック

この図が示していること

この図では、final が設計を安定させるためのロックとして働くことを表しています。

左側には、hp、currentArea、battleRank のように、戦士ごとに変わってよい状態値を置いています。

右側には、final confirmRule()、final class UltimateWarriorStyle、static final int MAX_WARRIOR_COUNT のように、変えてはいけないものを置いています。

中央の final ロックは、固定する、守る、設計意図を示すという役割を表しています。

この図から分かるのは、final が単なる禁止ではなく、変化してよい状態と、固定すべきルールを分けるための修飾子だということです。

final をドラゴンボール風に整理する

ドラゴンボール風にたとえると、final は「絶対に破ってはいけない決まり」をコードにしたものです。

final の使い方ドラゴンボール風のイメージ
final メソッドこの技の型は変えるな
final クラスこの戦士の型は完成形なので派生させるな
final フィールドこの数値は本部の決まりだから変えるな

オブジェクト指向では、自由に拡張できることは大きな強みです。

でも、本当に読みやすく安全な設計では、自由に変えてよい部分と、変えてはいけない部分が分かれています。

final は、その「ここは固定する」という線を引くための修飾子です。

この内容で押さえておきたいポイント

ポイント内容
final の基本意味それ以上変更させない
final メソッドオーバーライドできない
final クラス継承できない
final フィールド値を再代入できない
static finalクラス全体で共有する定数によく使う
final とオーバーライド変えてよいメソッドと変えてはいけないメソッドを分ける
final と継承派生を許すクラスと完成形のクラスを分ける
final と値状態として変わる値と、ルールとして固定する値を分ける

final を見たときは、「これは何を固定しているのか」と考えると理解しやすくなります。

メソッドならオーバーライドを止めています。

クラスなら継承を止めています。

フィールドなら値の変更を止めています。

この感覚がつかめると、final は単なる制限ではなく、設計を安定させるための大切な道具として見えてきます。