はじめに
Javaのコードを書いていて、引数は参照の値渡しなのにメソッドの返り値は参照を返してるなーと思ったので、初投稿もかねて書いてみました。
オブジェクトに対するGetter
Javaを書いたことある方なら、publicなフィールドは極力使わずに、Getter,Setterを作ろうみたいな話を聞いたことがあると思います。
これについてなんですが、今回はリストなどのオブジェクトを返すGetterを考えたいと思います。
まずは以下のコードから
public class TestList {
private List<String> lst;
public TestList(){
this.lst = new ArrayList<String>();
}
public List<String> getList(){
return lst;
}
public void setList(List<String> lst){
this.lst = lst;
}
}
まぁ、Listをラッピングしているクラスですね。次にメインを作ります。
public class Main {
public static void main(String[] args) {
TestList test = new TestList();
List<String> l = test.getList();
l.add("a");
l.add("b");
for (String s: test.getList()){
System.out.println(s);
}
}
}
これを実行すると以下のようになります。
a
b
これは外部(Main)からクラス内のprivateなリストを書き換えています。
つまりTestListクラスを作成した人からは意図されていない変更を与えることができる状況です。
これって多人数開発するとき危なくないですかね?
解決策
外部から変更されたくない場合は以下のようにArrayListをnewしてから返すように、getListを変更してやればいいです。
public class TestList {
private List<String> lst;
public TestList(){
this.lst = new ArrayList<String>();
}
public List<String> getList(){
return new ArrayList<String>(lst);
}
public void setList(List<String> lst){
this.lst = lst;
}
}
結論
僕自身Getterを作成する時に上のように書くべきか、下のように書くべきかの結論はいまいち出せてないです。しかし、カプセル化という視点で見た場合下のようなコードの方が隠蔽性は高いと思います。みなさんの意見もぜひお聞かせください。