はじめに
Java を勉強していると必ず目にするキーワードのひとつが final
です。
初心者にとっては「なんとなく変えられないもの」というイメージがあると思いますが、実際には 変数・メソッド・クラス で挙動が違い、理解していないとエラーや設計の失敗につながることがあります。
この記事では、Java 初心者やプログラマー転職を目指している方のために、final
の使い方を徹底的に解説します。
- 変数で使うとどうなるか
- メソッドで使うとどうなるか
- クラスで使うとどうなるか
- 実務での使いどころと注意点
さらに、サンプルコードを交えながら解説するので、すぐに理解できるようになります。
もし 独学でJavaを学びたい方 は、まず 絶対にJavaプログラマーになりたい人へ。 を読むことをおすすめします。それでも理解が難しい、あるいは転職を視野に入れている方は サイゼントアカデミー を活用してください。
finalとは?意味と基本ルール
Java の final
は 「これ以上変えられないようにする」 という意味を持つ修飾子です。
ただし、「変えられない」の中身は対象によって異なります。
- 変数 → 値を再代入できない
- メソッド → オーバーライドできない
- クラス → 継承できない
このように、どこに付けるかで意味が大きく変わるのです。
変数に final を付ける場合
基本の使い方
変数に final
を付けると、一度値を代入したら再代入できない という制約がつきます。
1 2 3 |
final int number = 10; number = 20; // コンパイルエラー |
プリミティブ型と参照型の違い
- プリミティブ型(int, double など)
値そのものが変更できない。 - 参照型(オブジェクト、配列など)
参照先は変えられないが、オブジェクト内部の状態は変更可能。
1 2 3 4 |
final List<String> list = new ArrayList<>(); list.add("Hello"); // OK list = new LinkedList<>(); // エラー |
この違いは初心者がよくつまずくポイントです。
blank final(ブランクfinal)
final 変数を 宣言だけして値を後で代入 する場合を「blank final」と呼びます。
これは 必ず一度だけ初期化しなければならない という制約があります。
1 2 3 4 5 6 7 8 |
class MyClass { final int value; MyClass(int v) { value = v; // コンストラクタで初期化 } } |
static final と定数
Java で定数を作る場合は static final を使います。
1 2 3 4 |
public class MathUtil { public static final double PI = 3.14159; } |
命名規則として 大文字+アンダースコア が推奨されます。
メソッドに final を付ける場合
基本の使い方
メソッドに final
を付けると、サブクラスでオーバーライドできなくなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Parent { public final void showMessage() { System.out.println("親のメッセージ"); } } class Child extends Parent { @Override public void showMessage() { // エラー System.out.println("子のメッセージ"); } } |
なぜ使うのか?
- クラス設計者が「このメソッドは絶対に変えてほしくない」と伝えるため
- セキュリティやバグ防止のため
- コンストラクタで呼ばれるメソッドを final にして予期せぬ動作を防ぐため
クラスに final を付ける場合
基本の使い方
クラスに final
を付けると、そのクラスを継承できなくなります。
1 2 3 4 |
public final class ImmutableClass { // 継承禁止 } |
代表例:String クラス
Java の String
クラスは final
です。
これにより、誰も String
を継承して挙動を変えることができません。
結果として 安全で予測可能な動作 が保証されています。
不変クラスを作るとき
クラスに final を付けることで、不変クラス(immutable class)を作るのに役立ちます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public final class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } } |
このようにすれば、Point クラスは生成後に状態が変わらないため、安全に扱えます。
final のメリット
- 意図を明示できる → 「この変数は変わらない」「このメソッドは上書きできない」など、コードの意味がわかりやすい
- バグを防止できる → 再代入やオーバーライドを禁止することで、思わぬ挙動を防ぐ
- 不変オブジェクトの実現 → マルチスレッド環境でも安全に利用できる
- 最適化の余地 → コンパイラや JVM が最適化できる可能性がある
final のデメリット・注意点
- 柔軟性を失う → 拡張や再利用が難しくなる
- 参照型の誤解 → final をつけても中身の変更は可能な場合がある
- 設計の硬直化 → 将来の変更を妨げる可能性
実務での使いどころ
- 定数の宣言 →
static final
を利用する - 安全性が重要なメソッド → final をつけてオーバーライド禁止にする
- 不変クラスの実現 → クラスとフィールドを final にする
- 引数やローカル変数の安全性 → final をつけて再代入を防ぐ
まとめ
Java の final
は単純そうに見えて、変数・メソッド・クラスで役割が大きく違います。
- 変数 → 値を再代入できない
- メソッド → オーバーライドできない
- クラス → 継承できない
正しく使うことで、安全で読みやすく、バグの少ないコードを書くことができます。
これから Java を本格的に学びたい方は、まずは 絶対にJavaプログラマーになりたい人へ。 を読んでみてください。
さらに体系的に学びたい方や、転職までサポートしてほしい方は サイゼントアカデミー が最適です。
コメント