對象須要知足一下三個條件纔是不可變對象:工具
一、對象建立之後其狀態就不能修改this
二、對象全部域都是final類型spa
三、對象是正確建立的(對象在建立期間,this引用沒有溢出)code
簡而言之就是將類聲明爲final,將全部的成員聲明爲私有的,對變量不提供set方法。將全部可變的成員聲明爲final。在get方法中不返回對象自己,而是克隆對象的拷貝。(可參考String類)。對象
final關鍵字可修飾類、方法和變量。在修飾類時,這個類是不容許被繼承。final類中的方法會被隱式的被指定爲final方法。修飾方法是爲了鎖定方法不被繼承類修改,即final方法不容許被修改,一個類的private方法會被隱式指定爲final類型。final修飾變量可分爲兩種狀況。1、修飾基本數據類型時,一旦被final修飾,這個變量的數值就不能被修改了。2、修飾引用類型變量時,則是讓它在初始化以後就不能指向其餘對象(可修改該引用變量的成員變量)。例如:blog
@Slf4j public class ImmutableExample1 { private final static Integer a = 1; private final static String b = "2"; private final static Map<Integer, Integer> map = new HashMap(); static { map.put(1, 2); map.put(3, 4); map.put(5, 6); } public static void main(String[] args) { map.put(1, 3); log.info("{}", map.get(1)); } }
雖然map聲明爲final對象,可是依然能夠往裏放入鍵值對。繼承
Collections.unmodifiableXXX:Collection、List、Set、Map等。rem
@Slf4j public class ImmutableExample2 { private static Map<Integer, Integer> map = Maps.newHashMap(); static { map.put(1, 2); map.put(3, 4); map.put(5, 6); map = Collections.unmodifiableMap(map); } public static void main(String[] args) { map.put(1, 3); log.info("{}", map.get(1)); } }
執行結果以下:get
發現執行結果爲拋出異常信息,不容許被修改。咱們能夠用這個方法來修飾不可變的集合對象。源碼
查看源碼的主要方法實現:
public class Collections { // Suppresses default constructor, ensuring non-instantiability. private Collections() { } private final Map<? extends K, ? extends V> m; UnmodifiableMap(Map<? extends K, ? extends V> m) { if (m==null) throw new NullPointerException(); this.m = m; } ... ... public V put(K key, V value) { throw new UnsupportedOperationException(); } public V remove(Object key) { throw new UnsupportedOperationException(); } public void putAll(Map<? extends K, ? extends V> m) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } ... ... }
其實就是將put方法等直接拋出異常,防止修改。
Googel經常使用的工具包Guava一樣也提供了不少不可變對象的方法如 ImmutableXXX:Collection、List、Set、Map等。