final const readonly
値を書き換えるつもりのない変数を宣言することがある。ローカル変数や関数の引数の場合もあれば、メンバ変数の場合もある。
Javaの場合、このような変数を宣言するときにはfinal
と書いておくと、コンパイル時にチェックできる*1。
C++にもconst
という似たものがある。詳しくは触れないけれど、Javaのfinal
より凝った機能を提供している。
さてC#にもきっとJavaのfinal
に相当するものがあるに違いない、そう思ってconst
と書いてみたのだが、どうもうまくいかない。
調べてみたところ、C#にはconst
のほかにreadonly
があり、求めていたのはこちらだったようだ。ただし、メンバ変数にしか使えない。
const
も値が書き換えられないという点は共通だが、静的に決まる値のみが許されるなど、「定数」としての意味が大きい。
まとめると次のようになる。
final | const | readonly | |
---|---|---|---|
Java | 変数の書き換え禁止 | ||
C++ | 変数の書き換え禁止 オブジェクトへのconst操作以外禁止 |
||
C# | 静的な定数 | メンバ変数の書き換え禁止 |
名前から連想する意味にもっとも近いのはC#のものだと思う。ローカル変数にもreadonly使いたいなぁ。
finallyの中でreturn
Javaのfinallyはよくできていて、tryやcatchの中から抜けるときは必ずfinallyが実行される。
- tryの中身の最後のステートメントが実行される
- returnやcatchしてない例外でメソッドごと抜けようとする
という場合にも、必ず実行される。
returnの場合には
- まず返値が求められて
- その後finallyの中身が実行されて
- さっき求めた返値になる
という徹底具合。ちょっとbegin0っぽい?
さて問題。tryの中でreturnして、finallyの中でもreturnしたら、返値はどうなるだろう?
public class FinallyQuiz { static int q() { try { return 0; } finally { return 1; } } public static void main(String[] args) { System.out.println("return value is " + q()); } }
パラメータで受け取った型のインスタンスを生成
C++のTemplateとJavaのGenericsを比べるとき、
- パラメータで受け取った型のインスタンスを生成できない
という話が出てくることがある。
import java.util.Vector; class Elem { } public class Test { // しかるべき方法で初期化された、要素数nのVector<T>がほしい static <T> Vector<T> make_n_vector(int n) { Vector<T> result = new Vector<T>(); while (n > 0) { T elem = new T(); // コンパイルエラー result.add(elem); n--; } return result; } public static void main(String[] args) { Vector<Elem> v = make_n_vector(10); } }
これがうまくいかない原因は、型パラメータTはコンパイルされた後で消えてしまうため、どのクラスをnewすればいいか分からなくなるという点につきる。
逆に言うと、コンパイルされた後でも消えない方法で型についての情報を渡すだけでうまくいく。
import java.util.Vector; class Elem { } public class Test2 { static <T> Vector<T> make_n_vector(Class<T> elem_class, int n) { Vector<T> result = new Vector<T>(); while (n > 0) { try { T elem = elem_class.newInstance(); // これならOK result.add(elem); } catch (IllegalAccessException iae) { // ここと } catch (InstantiationException ie) { // ここに失敗したときの処理 // この例なら RuntimeException とか AssertionError を投げるのがいいかな? } n--; } return result; } public static void main(String[] args) { // 呼び出し側で、型パラメータの代わりにクラスリテラルを渡す Vector<Elem> v = make_n_vector(Elem.class, 10); } }