什么是不可變的對象呢?我們都知道String是不可變的,如果有涉及大量的字符串拼接我們最好不要用String,雖然我們在代碼中可以這樣寫:
String str = "test";
str = "test1";
這樣寫是沒有錯的,這是不是和我們所說的String類型時不可變的違背了呢?其實不然,我們這里看到str“改變”了值,其實不是不是真正改變了,而是改變了str的引用。我們從下圖可以看到當定義String str = "test1"時,Java實際上做了這個操作(我們在這里不討論String關於使用new和不使用new,以及堆內存分配的問題)。
在我們再一次賦值str = "test1"時,Java實際上做了下面這個操作:
"test"變量其實並沒有改變,改變的只是str的引用,將str的引用重新指向在常量池中新創建的"test1"變量,這即是"不可變的對象"。
那么何為"不可變的對象引用"呢?字面意思當然就是和上面相反,允許它改變str的引用重新指向"test1"字符串變量。即是在定義變量時加上final關鍵字。我們看以下代碼:首先有一個User類,這個類中的name變量是普通變量,可以通過setName方法賦值。
1 package day_20_immutable; 2 3 /** 4 * @author 余林豐 5 * 6 * 2016年10月20日 7 */ 8 public class User { 9 private String name; 10 11 public String getName() { 12 return name; 13 } 14 15 public void setName(String name) { 16 this.name = name; 17 } 18 }
我們在main方法中來試驗一把final關鍵字的“不可變的對象引用”。
1 package day_20_immutable; 2 3 /** 4 * @author 余林豐 5 * 6 * 2016年10月20日 7 */ 8 public class Main { 9 private final User user = new User(); 10 /** 11 * @param args 12 */ 13 public static void main(String[] args) { 14 Main main = new Main(); 15 main.user.setName("keven"); 16 System.out.println(main.user.getName()); 17 main.user.setName("turbo"); //final關鍵字不影響本身是可改變的對象 18 System.out.println(main.user.getName()); 19 20 //main.user = new User(); //報錯,因為final關鍵字修飾的變量不能改變它的引用 21 22 } 23 24 }
以上便是“不可變對象”與“不可變的對象引用”的區別,為什么要區分這兩個概念,這是為后面Java多線程的線程安全先做下鋪墊。