Java 中的 String 真的是不可變嗎?

咱們都知道 Java 中的 String 類的設計是不可變的,來看下 String 類的源碼。java

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
    /** The value is used for character storage. */
    private final char value[];
    
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    
    // ...
    
}

能夠看出 String 類是 final 類型的,String 不能被繼承。其值 value 也就是對字符數組的封裝,即 char[],其值被定義成 private final 的,說明不能經過外界修改,即不可變。面試

String 真的 "不可變 " 嗎?

來看下面這個例子。數組

String str = "Python";
System.out.println(str); // Python

str = "Java";
System.out.println(str); // Java

str = str.substring(1);
System.out.println(str); // ava

你有可能會問:str 不是由 Python 變成 Java 了嗎?而後經過 substring 方法變成 ava 了嗎?安全

這實際上是初學者的一個誤區,從上面看 String 的結構能夠得知字符串是由字符數組構成的,str 只是一個引用而已,第一次引用了 "Python",後面變成了 "Java",而 substring 也是用 Arrays.copyOfRange 方法從新複製字符數組構造了一個新的字符串。微信

image

因此說,這裏的字符串並非可變,只是變動了字符串引用。架構

關於 substring 在 JDK 各個版本的差別能夠看這篇文章《注意:字符串substring方法在jkd6,7,8中的差別》,也能夠去看 substring 的各個版本的源碼。分佈式

String 真的真的真的 "不可變 " 嗎?

上面的例子確定是不可變的,下面這個就尷尬了。spa

String str = "Hello Python";
System.out.println(str); // Hello Python

Field field = String.class.getDeclaredField("value");
field.setAccessible(true);

char[] value = (char[])field.get(str);
value[6] = 'J';
value[7] = 'a';
value[8] = 'v';
value[9] = 'a';
value[10] = '!';
value[11] = '!';
System.out.println(str); // Hello Java!!

經過反射,咱們改變了底層的字符數組的值,實現了字符串的 「不可變」 性,這是一種騷操做,不建議這麼使用,違反了 Java 對 String 類的不可變設計原則,會形成一些安全問題。架構設計

是否是又漲姿式了?分享給你的朋友們吧!

更多幹貨推薦設計

1.史上最強 Java 中高級面試題整理

2.史上最強 Spring Boot & Cloud 教程整理

3.史上最強架構設計分佈式技術乾貨整理

更多請掃描下方的二維碼關注咱們的微信公衆號,乾貨每日推送!

Java技術棧

相關文章
相關標籤/搜索