目次
Javaのfinal修飾子とは?
finalを翻訳すると「最終」や「最後」のような意味となります。Javaでのfinal修飾子は、この言葉通り 「変更を許さない最後のもの」としてクラスや変数を宣言したい時に使用します。
final修飾子は、Javaのクラスやメソッド、変数に指定でき、指定する場所によって意味が変わるため、以降で詳しく解説していきます。final修飾子の意味を理解し、保守性が高いプログラムを作りましょう。
final修飾子を変数に指定した場合
変更(再代入)が禁止できる
変数の型の前に、final修飾子を指定すると、後から値が変更(再代入)できないfinal変数が宣言できます。
final int x = 100; // finalで宣言する変数
final変数に対して後から値を変更(再代入)するようなコードを記述すると、次のようなコンパイルエラーが発生します。
final int x = 100; // finalで宣言した変数 x = 200; // finalで宣言した変数の値を変更(再代入)
final のローカル変数 x には代入できません。
クラス変数にfinalを指定すると定数になる
final修飾子をクラス変数に指定すると定数になります。定数にはインスタンスが不要なため、static修飾子と合わせて宣言を行うのが一般的です。
class Sample { public static final String finalTest = "定数の値"; }
final修飾子をクラスに指定した場合
次は、final修飾子をクラス付けた場合、どのような意味になるのか解説します。
継承ができないクラスを作れる
Javaのクラスにfinal修飾子を指定すると、継承ができないクラスを作れます。
Javaではクラスの継承を行うことで、親クラスの機能を引継ぎつつ、子クラス側で柔軟に機能の拡張や、親クラスのメソッドの振る舞いを変えることができますが、final修飾子をクラスに指定すると、クラスの継承を禁止することができます。
final class FinalClass { }
final 修飾子がついたクラスを継承すると、次のようなコンパイルエラーが発生します。
class FinalSubClass extends FinalClass { //extendsでfinal修飾子がついたクラスを継承 }
型 FinalSubClass は final クラス FinalClass をサブクラス化できません
finalクラスの使いどころ(いつfinalにするのか)
final修飾子が付いたクラスは、継承できないクラスだと解説しました。言い換えれば、finalクラスはそれ以降の改変ができない、最終的なクラスのバージョンともいえます。
では、finalクラスはいつ使うのでしょうか?これが全てではありませんが、以下にfinalクラスの使いどころの例を挙げていきます。
【継承連鎖を防ぐ】
以下は、クラスの継承関係がいくえにも重なったコードの例です。
class Car { /* ... */ } class Prius extends Car { /* ... */ } class PriusPHV extends Prius { /* ... */ } class Prius2015PHV extends PriusPHV { /* ... */ } class Prius2016PHV extends Prius2015PHV { /* ... */ }
上のコードを見ても分かる通り、継承関係が深いため、処理の内容を確認するだけで、複数のクラスのコードを見る必要があり、さらにメソッドのオーバーライドの関係についても把握する必要があります。
おそらく、このクラスの利用者は、全体像を掴むのに相当な時間を強いられるでしょう。
クラスの継承は、Javaをはじめとするオブジェクト指向言語の利点ですが、過度な継承構造はコードの保守性を下げるため避けるべきです。適切なところでfinal修飾子をクラスに付け、それ以降のクラスの継承が発生しないように制御しましょう。
【とりあえずfinal修飾子を付けるのもアリ】
システム開発では多くの開発者が関わります。そういった時、プログラマーによっては、他人が作成したクラスのコードを編集するのに抵抗があり、安易にクラスを継承したりする事があります。
継承クラスを作成する前に、元のクラスを編集したほうがよいか検討する必要あるため、そのきっかけとして、クラスにfinal修飾子をとりあえず付けておくのも、1つの案です。
final修飾子メソッドを指定した場合
final修飾子はメソッドにも付けられます。メソッドにfinal修飾子を付けると、どのような意味になるのか解説します。
オーバーライドできないメソッドを作れる
メソッドにfinal修飾子を付けると、オーバーライドを禁止するメソッドを作ることができます。
Javaでは、親クラスを継承した子クラス側で、親クラスと同じメソッド名、同じ引数のメソッドを用意すると、親クラスのメソッドを書き換えることができます。final修飾子をメソッドに指定すると、子クラスによるメソッドの書き換えを禁止できます。
class SampleClass { final void finalMethod() { // 処理 } }
final 修飾子がついたメソッドをオーバーライドすると、次のようなコンパイルエラーが発生します。
class SubClass extends SampleClass { void finalMethod() { //final修飾子が付いた親クラスのメソッドをオーバーライド } }
SampleClass からの final メソッドをオーバーライドできません
finalメソッドの使いどころ(いつfinalにするのか)
final修飾子が付いたメソッドは、オーバーライドが禁止であることを解説しました。メソッドにfinal修飾子を付けるかどうは、ネットでもさまざまな議論があり、判断が難しいところですが、以下に、finalメソッドの使いどころの例を挙げていきます。
【メソッドが完成している事を伝えるとき】
メソッドの中の処理が完成しており、これ以上の変更の余地がないような場合、final修飾子を付けことで、完成品であることを表現できます。
【オーバーライドされると問題が発生するとき】
メソッドの処理を書き換えられると、クラス全体の動作に問題が発生する場合、final修飾子をメソッドに指定して、クラスが安全に動作するようにします。
Javaのfinal修飾子を使いこなそう
Javaのfinal修飾子の使い方や、いつfinal修飾子を使うのかについて解説してきました。
final修飾子の意味を理解し、質の高いプログラムを作って、Javaエンジニアとしてのスキルをアップしていきましょう。
- final修飾子は変数、クラス、メソッドに指定できる
- final修飾子を変数に指定すると再代入ができない定数になる
- final修飾子をクラスに指定すると継承を禁止するクラスになる
- final修飾子をメソッドに指定するとオーバーライドを禁止できる
規模大きいシステムや、同じ値を頻繁に使うプログラムの場合、定数を積極的に活用しましょう。定数として宣言しておけば、もし、後からの値を変更する場合があっても、定数の宣言をしている所の値をすれば、その定数を参照しているプログラムすべてに変更した値が反映できます。