フィールドの隠蔽
Javaのフィールド(メソッドの外で宣言される変数)は、ローカル変数(メソッドの中で宣言される変数)と名前が重なってもエラーになりません。名前が重なった場合には、「隠蔽」という現象が起こります。たとえば、public class Test{
String strTest="フィールド";
public static void main(String[] args){
String strTest="ローカル変数";
System.out.println(strTest);
}
}
のようなコードで、printlnメソッドで実際に表示されるstrTestはローカル変数の方です。つまり、フィールド側のstrTestがローカル変数のstrTestによって「隠蔽」されるわけです。String strTest="フィールド";
public static void main(String[] args){
String strTest="ローカル変数";
System.out.println(strTest);
}
}
一般的には、ローカル変数ではなくフィールドを明示的に指定するためには「thisキーワードを使えばよい」ということになっているようです。たとえば、こんな感じです。
public class Person{
private String name;
public void setName(String name){
this.name = name;
}
}
上のコードで、this.name = name の左辺はフィールド、右辺はローカル変数(引数)を表すことになります。しかし、thisを使ってフィールドとローカル変数を区別する方法では、困ったことが2つほどあります。private String name;
public void setName(String name){
this.name = name;
}
}
タイプミスに弱い
1つは、タイプミスに対して、チェックが弱くなるということです。たとえば、次のようなコードはコンパイルが通ってしまいます。どこが間違っているか、分かりますか?public class Person{
private String name;
public void setName(String nema){
this.name = name;
}
}
setNameメソッドの引数の宣言が「name」ではなく「nema」になっているため、this.name = name の行は、右辺も左辺もフィールドと解釈されます。この手のバグは非常に見つけづらいです。private String name;
public void setName(String nema){
this.name = name;
}
}
staticメソッドではthisが使えない
もう1つの困ったことは、staticメソッドの中ではthisキーワードが使えないことです。冒頭のコードでは、printlnメソッドに引数this.strTestを渡すと、次のようなコンパイルエラーになります。Test.java:5: static でない 変数 this を static コンテキストから参照することはで
きません。
System.out.println(this.strTest);
^
エラー 1 個
きません。
System.out.println(this.strTest);
^
エラー 1 個
フィールド名のプリフィクスにアンダースコア
「フィールドとローカル変数では同じ名前を使わない」という取り決めをすれば、これら2つの困ったことは起こりません。そこで、よく使われる手は、「フィールド名にアンダースコアのプリフィクスをつける」というものです。こんな感じです。public class Person{
private String _name;
public void setName(String name){
_name = name;
}
}
このような方法を採れば、タイプミスがコンパイルをすり抜けてしまうこともありませんし、staticメソッドの中から参照する場合も問題はありません。private String _name;
public void setName(String name){
_name = name;
}
}
しかし問題が・・・・
この書き方は、文法的には間違いではありませんし、コンパイルも通ります。ただ、Sunの提唱するコーディング規約(code convention)には、「変数名をアンダースコアやドル記号で始めないこと」と書かれています。さて、どうしましょう。1つの方法は、アンダースコア以外のプリフィクスを選ぶ方法です。フィールドなので、fにしますか?でもfloatの頭文字もfですし、自明ではありません。fieldをプリフィクスにするか、3文字に縮めてfldとかですかね。もしくは、アンダースコアを変数名の後に置く(ポストフィクスにする)とか。いずれにしても、アンダースコアのプリフィクスほど見た目で分かりやすくはありません。
もう1つの方法は、「規約を無視してアンダースコアを使う」というものです。他の規約を無視するといろいろ支障がありそうですが、既にアンダースコアをフィールド名のプリフィクスに使っている人も結構いるようですし「ダメなものはダメ」以上の理由があるようには、どうも思えないんですよね。
将来的には、Javaの文法が変わってアンダースコアのプリフィクスが使えなくなるという可能性がなくもありません。Sunが規約を変えてアンダースコアのプリフィクスをOKにしてくれたらいいと思うんですけど、どうでしょう。
参照:Sunの提唱するコーディング規約
http://java.sun.com/docs/codeconv/html/CodeConventions.doc8.html#367
投稿:竹形 誠司[takegata]/2008年 05月 25日 04時 10分
/更新:2008年 05月 25日 04時 18分