通過反射還是可以修改的。
public static void stringReflection() throws Exception {
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//獲取String類中的value字段
Field valueField = String.class.getDeclaredField("value");
//改變value屬性的訪問權限
valueField.setAccessible(true);
char[] value = (char[]) valueField.get(s);
//改變value所引用的數組中的第5個字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
}
===為什么string是不可變對象,有什么優勢?
底層使用private final char value[];有一個private final的數組
1.節省堆空間,string對象創建后會存入字符串常量池中,同一個string可以有不同的指針同時指向。
保證唯一性,多線程處理同一個string的時候不用擔心線程問題,因為不可變。
2.安全性考慮。
---數據庫賬號密碼
---網絡編程的端口號和ip
---類加載器加載類的時候
都是通過string來傳遞,如果可變會造成系統漏洞
3.用於當hashmap的鍵特別適合,因為hashcode不變不需要重復計算,直接緩存這個hashcode
===如何創建一個不可變類?
簡述:成員變量是private final類型,初始化用構造函數克隆的方式初始化,沒有set方法,get方法使用克隆的方式進行訪問。
---類定義:final修飾類,不能夠繼承
---成員變量:1.成員變量設為私有private final,通過構造器初始化;2.不為成員變量設置set方法;3.如果有可變對象那么初始化的時候必須使用clone的方式進行初始化,新建一個對象初始化,否則會影響到原有的對象。
---方法:1.對於不可變對象中的可變對象的訪問方式:比如說有個map,那么如何獲取呢?get方法不能夠直接返回對象本身,而是通過克隆來返回對象,這樣修改原始數據不會影響新建的這個數據。2.同時構造器進行初始化對象的時候必須創建一個新的hashmap來復制構造函數的入參map,就是克隆
目的:比如我有三個屬性int,string,hashmap用來初始化了一個不可變對象,那么我獲取到對象中的hashmap的引用,獲取引用使用hasmap.clone()方法,那么這個引用指向新的數組地址,但是如果hashmap內部有對象引用的話,是不會進行復制的,還是指向了原有的對象。
===hashmap的clone方法是深拷貝還是淺拷貝呢?
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
這個是entry克隆的內部實現,鍵值對都會進行新建。
如果是引用類型的時候,只是復制了引用,所以修改新的或者舊的引用的時候都是指向同一個堆空間中的對象的。
1.HashMap的clone方法生成新的對象,新的對象有自己獨立的存儲空間。
2.雖然HashMap的clone方法生成了新的對象,但新的HashMap和原來的HashMap所存儲的引用類型都是指向的同一存儲空間。
這就導致在對HashMap中的元素進行修改的時候,即對數組中元素進行修改,會導致原對象和clone對象都發生改變,但進行新增或刪除就不會影響對方,因為這相當於是對數組做出的改變,clone對象新生成了一個數組。