どーも、ふぎとです。
今回はfinal変数と不変オブジェクトについて
まとめてみました。
##final変数
final変数とは、final修飾子を指定した変数のこと。
その性質は「変更不可・読み込み専用」と呼ばれる
が、厳密には「再代入不可の変数」。
final int i = 3;
i = 5; //再代入によるコンパイルエラー
上では、基本型(int型)変数iにfinalを指定している。
基本型変数は、変数の値に「値そのもの」が保持される
変数だ(詳細は『基本型変数の代入と参照型変数の代入
の違い』を参照)。そのため、「値そのもの」を入れ替
える再代入はコンパイルエラーになる。つまり、基本型
変数に限って言えば、final変数は「変更不可」である
ように見える。
話をややこしくしているのは、final指定の参照型変数だ。
final StringBuilder sb = new StringBuilder("123");
sb = new StringBuilder("456"); //コンパイルエラー
final StringBuilder sb2 = new StringBuiler("789");
sb.append("★"); //コンパイルエラーにならない!
System.out.println(sb2); //"789★"が出力される
上の例では、参照型変数sbとsb2に対して操作をしている。
ここで、final変数の性質を「変更不可」と理解していると、
sbへの操作がエラーになり、sb2への操作がそうならない事
の意味がわからなくなる。
ここで、参照型変数が保持している値を思い出してみると、
これは「オブジェクトへの参照」であった。つまり、sbや
sb2が持っているのは、"123"や"789"という「値そのもの」
ではない。彼ら(?)が持っているのは、あくまでも「"1
23(456)"という状態となったオブジェクトへの参照」なのだ。
この仕組みと、final変数の厳密な定義「再代入不可」とを考
えに入れると、上の例を理解することができる。すなわち、
sbに対する "sb = new StringBuilder("456")"という操作、これ
は「新たな参照の値をsbに再代入する」という操作だ。よっ
て、final変数の性質により、コンパイルエラーがでる。一方、
"sb2.append("★")" の操作、これは「"789"という状態を持つ
オブジェクトの状態を"789★"という状態に変える」という操
作となる。要するに、sb2への「オブジェクトへの参照値」の
再代入は起こっていない。そのためエラーとならないのである。
##不変オブジェクト
final変数が「再代入不可」の性質を持つ一方で、不変オブジェ
クトは「オブジェクトの状態変更」をも禁じている。つまり、
上の例でいうところの "sb.append("★")" の操作もできないのが
不変オブジェクトなのだ。
##まとめ
・final変数は「再代入不可」の性質を持つ
・参照型変数をfinal指定すると、「参照先の変更」は
できないが「最初に参照したオブジェクトの状態変
更」はできる
・「最初に参照したオブジェクトの状態変更」もできない
オブジェクトを「不変オブジェクト」と呼ぶ
...
では今回はこの辺で。ふぎとでした。
(P.S.)記事の内容への指摘などあれば
遠慮なくお知らせくださいm(__)m