為什么 String 類不可變
- final修飾符:
String
類被聲明為final
,這意味著它不能被繼承。因此,無法創建String
的子類來修改其行為。 - 私有字符數組(char[]):
String
類內部使用私有的字符數組來存儲字符串的內容。這個字符數組是final
的,即它的引用不能被修改。一旦字符串被創建,它的內容就不能被更改。 - 不提供可變方法:
String
類沒有提供用于修改字符串的方法。例如,沒有類似于setCharAt(int index, char ch)
的方法,而是提供了返回新字符串的方法,比如substring()
、concat()
等。
有沒有辦法直接修改 String 對象的值而不是 重新創建一個字符串對象
其實是有的,Java 提供了反射機制是可以獲取到私有的字段并且設置其字段值的。
關于Java反射的介紹
直接修改字符串的值,會重新創建一個字符串對象
public void test01() throws Exception {Field value = String.class.getDeclaredField("value");value.setAccessible(true);char[] chars = null;String str = "hhhhh";chars = (char[]) value.get(str);// identityHashCode() 基于對象地址返回哈希碼System.out.println("字符串地址:" + System.identityHashCode(str) +" 值:" + str +" value地址:" + System.identityHashCode(chars));str = "hello world";chars = (char[]) value.get(str);System.out.println("字符串地址:" + System.identityHashCode(str) +" 值:" + str +" value地址:" + System.identityHashCode(chars));}// 輸出
字符串地址:721748895 值:hhhhh value地址:1642534850
字符串地址:1724731843 值:hello world value地址:1305193908
使用反射直接修改字符串數組的值
public void test02() throws Exception {Field value = String.class.getDeclaredField("value");value.setAccessible(true);char[] chars = null;String str = "hello world";chars = (char[]) value.get(str);System.out.println("字符串地址:" + System.identityHashCode(str) +" 值:" + str +" value地址:" + System.identityHashCode(chars));for (int i = 0; i < chars.length; i++) {chars[i] = 'a';}chars = (char[]) value.get(str);System.out.println("字符串地址:" + System.identityHashCode(str) +" 值:" + str +" value地址:" + System.identityHashCode(chars));}
// 輸出
字符串地址:721748895 值:hello world value地址:1642534850
字符串地址:721748895 值:aaaaaaaaaaa value地址:1642534850
使用反射修改字段的值
public void test03() throws Exception {Field value = String.class.getDeclaredField("value");value.setAccessible(true);char[] chars = null;String str = "hello world";chars = (char[]) value.get(str);System.out.println("字符串地址:" + System.identityHashCode(str) +" 值:" + str +" value地址:" + System.identityHashCode(chars));char[] tmp = {'1','2','3'};value.set(str,tmp);chars = (char[]) value.get(str);System.out.println("字符串地址:" + System.identityHashCode(str) +" 值:" + str +" value地址:" + System.identityHashCode(chars));}
// 輸出
字符串地址:721748895 值:hello world value地址:1642534850
字符串地址:721748895 值:123 value地址:1724731843
當然這種直接修改char[]
數組,繞過了String
類安全機制的操作是不推薦的,因為它可能導致程序在運行時產生不可預測的行為,并且可能破壞其他代碼對字符串不可變性的依賴。
使用反射修改違背了 Java 語言中字符串不可變性的設計原則。在實際開發中,最好遵循這個設計原則,以確保代碼的可靠性和可維護性。如果需要可變的字符串,建議使用StringBuilder
或StringBuffer
類。