不可變的對象指的是一旦創建之後,它的狀態就不能改變。String類就是個不可變類,它的對象一旦創建之後,值就不能被改變了。
閱讀更多: 爲什麼String類是不可變的
不可變對象對於緩存是非常好的選擇,因爲你不需要擔心它的值會被更改。不可變類的另外一個好處是它自身是線程安全的,你不需要考慮多線程環境下的線程安全問題。
閱讀更多: Java線程教程以及Java多線程面試問題
Here I am providing a way to create immutable class via an example for better understanding.
下面是創建不可變類的方法,我也給出了代碼,加深理解。
要創建不可變類,要實現下面幾個步驟:
- 將類聲明爲final,所以它不能被繼承
- 將所有的成員聲明爲私有的,這樣就不允許直接訪問這些成員
- 對變量不要提供setter方法
- 將所有可變的成員聲明爲final,這樣只能對它們賦值一次
- 通過構造器初始化所有成員,進行深拷貝(deep copy)
- 在getter方法中,不要直接返回對象本身,而是克隆對象,並返回對象的拷貝
爲了理解第5和第6條,我將使用FinalClassExample來闡明。
import java.util.HashMap;
import java.util.Iterator;
/**
* @Description
* @Author hzmoudaen
* @Since 2014-5-11
*/
public final class FinalClassExample {
private final int id;
private final String name;
private final HashMap<String, String> testMap ;
public int getId(){
return id;
}
public String getName(){
return name;
}
/** ------------------------------------------------------------1-------------------
* 訪問可變對象 克隆
* @return
*/
@SuppressWarnings("unchecked")
public HashMap<String, String> getTestMap(){
return (HashMap<String, String>)testMap.clone();//返回對象的複製
}
/**------------------------------------------2--------------------------
* 訪問可變對象 複製
* @return
*/
// public HashMap<String, String> getTestMap(){
// return testMap;//直接返回對象的引用
// }
/**-----------------------------------------3------------------------------
* 深複製
* @param i
* @param n
* @param hm
*/
public FinalClassExample(int i,String n,HashMap<String, String>hm){
System.out.println("Perfoming deep copy for object inititalization");
this.id = i;
this.name = n;
HashMap<String, String> tempMap = new HashMap<String, String>();
String key;
Iterator<String> it = hm.keySet().iterator();
while(it.hasNext()){
key = it.next();
tempMap.put(key, hm.get(key));
}
this.testMap = tempMap;
}
/**---------------------------------------4------------------------------------
* 淺複製
* @param i
* @param n
* @param hm
*/
// public FinalClassExample(int i,String n,HashMap<String, String>hm){
// System.out.println("Perfoming shallow copy for object inititalization");
// this.id = i;
// this.name = n;
// this.testMap = hm;
// }
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("1", "first");
map.put("2", "second");
String s = "original";
int i = 10;
FinalClassExample example = new FinalClassExample(i, s, map);
//下面看一個複製的域還是引用
System.out.println(s==example.getName());
System.out.println(map == example.getTestMap());
//打印example的值
System.out.println("example id="+example.getId());
System.out.println("example name="+example.getName());
System.out.println("example testmap = "+ example.getTestMap());
//改變局部變量的值
i = 20;
s ="modify";
map.put("3", "third");
//打印值
System.out.println("example id after local variable change ="+example.getId());
System.out.println("example name after local variable change ="+example.getName());
System.out.println("example testmap after local variable change = "+ example.getTestMap());
HashMap<String, String> hm = example.getTestMap();
hm.put("4", "new");
System.out.println("example testMap after changing variable from accessor methords:"+example.getTestMap());
}
}
輸出:
Perfoming deep copy for object inititalization
true
false
example id=10
example name=original
example testmap = {2=second, 1=first}
example id after local variable change =10
example name after local variable change =original
example testmap after local variable change = {2=second, 1=first}
example testMap after changing variable from accessor methords:{2=second, 1=first}
現在我們註釋掉深拷貝的構造器,取消對淺拷貝構造器的註釋。即註釋掉代碼-----1---和代碼-------3----,打開代碼------------2--------,---4---。輸出:
Perfoming shallow copy for object inititalization
true
true
example id=10
example name=original
example testmap = {2=second, 1=first}
example id after local variable change =10
example name after local variable change =original
example testmap after local variable change = {3=third, 2=second, 1=first}
example testMap after changing variable from accessor methords:{3=third, 2=second, 1=first, 4=new}
從輸出可以看出,HashMap的值被更改了,因爲構造器實現的是淺拷貝,而且在getter方法中返回的是原本對象的引用