Javaには変数の値を自由に変更できないように「static final」を使用することがあります。
この記事では、static finalの、
- final修飾子の意味
- final修飾子の基本的な使い方
- クラスにfinalを指定する方法
- メソッドにfinalを指定する方法
- クラス定数の初期化
- 配列にfinalを指定する方法
- ListやMapにfinalを指定する方法
という基本的な内容から、などの応用的な使い方に関しても解説していきます。
今回はそんなstatic finalの処理について、さまざまな方法をわかりやすく解説します!
なお、Javaの記事については、こちらにまとめています。
final修飾子とは
変数は基本的に値を自由に変更できますが、一度値を設定したら変更されない変数のことを「定数」と呼びます。final修飾子を指定した変数は、基本的に規定値など一度値を設定したら変更する必要がない値に用いられます。
以下はfinal修飾子を指定して、クラス定数を宣言しています。クラス定数を指定する場合は、変数の宣言の頭にstatic finalを記述します。
public static final double DNUM = 3.1415926535
final修飾子は変数以外にもメソッドやクラスにも指定することができます。
変数、メソッド、クラスにfinal修飾子を指定した場合は以下のようになります。
- クラスにfinalを指定した場合は、そのクラスを継承することはできません。
- メソッドにfinalを指定した場合は、そのメソッドをオーバーライドすることはできません。
- 変数にfinalを指定した場合は、その変数の値を変更することはできません。
また、final修飾子を指定した定数は、通常の変数と区別するために変数名の英数字を大文字で記述することが多いです。
final修飾子の基本的な使い方
以下にfinal修飾子を使用した基本的な使い方を記述します。
public class Main { //static finalを使用してクラス定数を宣言する public static final double DNUM = 3.1415926535; public static void main(String[] args) throws Exception { System.out.println("DNUM : " + DNUM); } }
実行結果 DNUM : 3.1415926535
サンプルでは、クラスの直下にstatic finalでdouble型のクラス定数を宣言しています。mainメソッドで、クラス定数の値が正しく設定されていることを確認できます。
また、定数は先述したとおり一度値を設定したら再度設定することはできませんのでメソッド内で以下のように定数を設定してもコンパイルエラーとなります。
DNUM = 100.0;
クラスにfinalを指定する方法
以下にfinal修飾子をクラスに指定した場合のサンプルを記述します。
前述したとおり、クラスにfinal修飾子を指定すると、そのクラスは継承できなくなります。
final public class ParentClass { public static void main(String[] args) { System.out.println("ParentClass"); //クラスのオブジェクトを生成 SubClass sb = new SubClass(); sb.subMethod(); } }
public class SubClass extends ParentClass{ public void subMethod(){ System.out.println("SubClass"); } }
このサンプルでは親クラスにあたるParentClassをfinal修飾子で指定しているため、その子クラスであるSubClassで、extendsによる親クラスの継承を指定しても、以下のエラーとなります。
型 SubClass は final クラス ParentClass をサブクラス化できません
メソッドにfinalを指定する方法
以下にfinal修飾子をメソッドに指定した場合のサンプルを記述します。前述したとおりメソッドにfinal修飾子を指定すると、そのメソッドはオーバライドできなくなります。
public class ParentClass { final public void ParentMethod(){ System.out.println("ParentMeshotd"); } }
public class SubClass extends ParentClass{ public void ParentMethod(){ System.out.println("parentMethod"); } }
このサンプルでは親クラスにあたるParentClassのメソッドをfinal修飾子で指定しているため、その子クラスであるSubClassで、親クラスのメソッドを指定しても、以下のエラーとなります。
ParentClass からの final メソッドをオーバーライドできません
クラス定数の初期化
定数は基本的に宣言時に値を設定し、一度値を代入したら再設定はできません。そのため、宣言時に値を設定しなかった場合、メソッド内で初めて値を設定しようとしてもコンパイルエラーが発生します。
定数の数が多く、宣言と初期化処理を分けたい場合は、staticイニシャライザ内なら定数を初期化することが可能です。以下に定数の宣言と、定数の初期化処理を分けて記載するためのサンプルを記述します。
public class Main { public static final int NUM1; public static final int NUM2; //static内で定数の初期化 static { NUM1 = 10; NUM2 = 20; } public static void main(String[] args) throws Exception { System.out.println("NUM1 : " + NUM1); System.out.println("NUM2: " + NUM2); } }
実行結果 NUM1 : 10 NUM2 : 20
配列にfinalを指定する方法
final修飾子は、配列にも指定することができます。しかし、配列をfinalで宣言しても変更できないのは配列のインスタンスであり、配列の要素を変更することは可能です。
public class ParentClass { //配列のfinal修飾子を指定する public static final int[] FOO = {0, 1, 2, 3}; public static void main(String[] args) { //finalを指定しても配列の要素は変更できる。 FOO[0] = 10; System.out.println(FOO[0]); } }
実行結果 10
実行結果からわかるように、final修飾子で配列を宣言しても要素自体は変更できてしまいます。そのため、保持している要素を変えられたくない場合は、ListやMapなどの動的配列を使用する方法があります。
ListやMapをfinal修飾子を指定した定数として扱う方法は、次項で詳しく解説します。
ListやMapにfinalを指定する方法
定数は基本的に一度値を設定したら変更できませんが、ListやMapなどの動的配列をstatic finalで指定しても、値の変更ができてしまいます。
もし、ListやMapなどをfinal修飾子を指定した定数として扱いたいのなら、CollectionsクラスのunmodifiableListメソッドを使用する方法があります。
unmodifiableListメソッドは、ListやMapを読み取り専用とする機能で、設定したListやMapに値の変更や追加などを実施すると、UnsupportedOperationExceptionの例外が発生します。
そのため、unmodifiableListメソッドを使用すれば、定数として使用できることが可能となります。
以下にunmodifiableListメソッドを使用した、定数化の方法を記述します。
public class Main { //unmodifiableListを使用して定数を宣言する public static final List<String> LIST_MOD = Collections.unmodifiableList(new ArrayList<String>() {{ add("apple"); add("orange"); add("melon"); }} ); public static void main(String[] args) throws Exception { System.out.println(LIST_MOD.get(0)); System.out.println(LIST_MOD.get(1)); System.out.println(LIST_MOD.get(2)); } }
実行結果 apple orange melon
finalについてもっと詳しく知りたい方へ
この記事で解説したようにfinal修飾子を指定すれば、その変数やクラス、メソッドの内容を自由に変更することができなくなります。そのため、不用意に値やクラス、メソッドの内容を変えられたくない場合はfinal修飾子を指定するのが望ましいと言えます。
finalのさまざまな使い方については、以下の記事にまとめていますので、「final修飾子についてもっと知りたい!」という方はぜひ参考にしてくださいね!
static修飾子の使い方について
この記事で紹介したstatic修飾子は。主にクラスをインスタンス化せずに、直接メソッドや変数にアクセスできる便利な修飾子です。そんなstatic修飾子を活用する方法については、以下の記事で詳細に解説していますので、気になった方はぜひ参考にしてください!
まとめ
ここでは、static finalの意味や基本的な使い方、初期化の方法やList、Mapの定数化などを説明しました。
final修飾子は、変更する予定のない規定値などを設定する場合に、変数と区別するために定数としてよく使用されます。もしstatic finalの記述方法を忘れてしまったら、この記事を思い出してくださいね!