如何寫一個不可變類

本文由 ImportNew - 唐小娟 翻譯自 Journaldev。歡迎加入Java小組。轉載請參見文章末尾的要求。

   不可變的對象指的是一旦創建之後,它的狀態就不能改變。String類就是個不可變類,它的對象一旦創建之後,值就不能被改變了。

   閱讀更多: 爲什麼String類是不可變的

   不可變對象對於緩存是非常好的選擇,因爲你不需要擔心它的值會被更改。不可變類的另外一個好處是它自身是線程安全的,你不需要考慮多線程環境下的線程安全問題。

   閱讀更多: Java線程教程以及Java多線程面試問題

   Here I am providing a way to create immutable class via an example for better understanding.

下面是創建不可變類的方法,我也給出了代碼,加深理解。

要創建不可變類,要實現下面幾個步驟:

  1. 將類聲明爲final,所以它不能被繼承
  2. 將所有的成員聲明爲私有的,這樣就不允許直接訪問這些成員
  3. 對變量不要提供setter方法
  4. 將所有可變的成員聲明爲final,這樣只能對它們賦值一次
  5. 通過構造器初始化所有成員,進行深拷貝(deep copy)
  6. 在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方法中返回的是原本對象的引用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章