Menu
CoddyTech

finalキーワード

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 13/87。

Javaのfinalキーワードは変更を防ぎます。変数、メソッド、クラスに適用でき、それぞれ異なる効果があります。

変数に適用すると、finalはそれを定数にします。一度値を代入すると、その値は変更できません。

public class Circle {
    private final double PI = 3.14159;
    private final double radius;
    
    public Circle(double radius) {
        this.radius = radius;  // constructor 内で一度だけ代入できる
    }
    
    public void setRadius(double r) {
        // this.radius = r;  // エラー!final 変数には再代入できない
    }
}

final変数は、宣言時またはコンストラクター内で初期化する必要があります。その後、再代入しようとするとコンパイルエラーが発生します。

参照型の場合、finalは参照が別のオブジェクトを指せないことを意味しますが、オブジェクトの内容は変更できます。

private final StringBuilder name = new StringBuilder("John");

// name = new StringBuilder("Jane");  // エラー!再代入できません
name.append(" Doe");  // OK!オブジェクトの内容は変更できます

フィールドにfinalを使うと、意図が明確に伝わります。初期化後にこの値を変更してはならないことを、ほかの開発者に伝えられます。これは、設定値、ID、またはオブジェクトの存続期間を通じて一定に保たなければならないデータに特に役立ちます。

final メソッドはサブクラスでオーバーライドできません:

class Base {
    public final void greet() {
        System.out.println("Hi");
    }
}
class Child extends Base {
    // public void greet() { }  // エラー!greet() は Base で final として宣言されています
}

final クラスはまったく拡張できません。Stringはfinalクラスなので、どのクラスもこれを拡張できません。

final class Config { }
// class MyConfig extends Config { }  // エラー!Config は final です
challenge icon

チャレンジ

簡単

finalキーワードを使って、学生の登録後に変更されてはならないデータを保護するStudent登録システムを作りましょう。

コードを整理するために、2つのファイルを作成します。

  • Student.java:設定後に永久に変更できない情報を持つStudentクラスを作成します。
    • finalフィールドstudentId(String)— 作成時に割り当てられ、その後は変更できません
    • finalフィールドenrollmentYear(int)— 学生が入学した年で、こちらも変更できません
    • 通常のprivateフィールドname(String)— 学生が名前を変更した場合に更新できます
    • 3つの値を受け取り、フィールドを初期化するコンストラクター
    • 学生IDを取得するためのゲッターgetStudentId()
    • 入学年を取得するためのゲッターgetEnrollmentYear()
    • 名前を取得するゲッターgetName()と、名前を設定するセッターsetName()
    • 次の値を返すメソッドgetInfo():"ID: [studentId] | Name: [name] | Enrolled: [enrollmentYear]"
  • Main.java:Studentオブジェクトを作成し、名前を更新して情報を表示します。入力は4つです。学生ID、最初の名前、入学年、更新後の新しい名前です。次の2行を出力します。
    • 名前を変更する前の学生情報
    • 名前を変更した後の学生情報

入力は順に4つ受け取ります:studentId(String)、name(String)、enrollmentYear(int)、newName(String)。

finalフィールドが学生のIDと入学年をどのように保護するかに注目してください。これらは変更されるべきではない永久的な記録ですが、名前はセッターを使って更新できます。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み込む
        String studentId = scanner.nextLine();
        String name = scanner.nextLine();
        int enrollmentYear = scanner.nextInt();
        scanner.nextLine(); // 改行文字を読み飛ばす
        String newName = scanner.nextLine();
        
        // TODO: 初期値を使ってStudentオブジェクトを作成する
        
        // TODO: 名前を変更する前の学生情報を表示する
        
        // TODO: セッターを使って学生の名前を更新する
        
        // TODO: 名前を変更した後の学生情報を表示する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Javaオンラインコンパイラ