日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 字符串赋值_灵魂拷问:为什么 Java 字符串是不可变的?

發布時間:2024/9/19 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 字符串赋值_灵魂拷问:为什么 Java 字符串是不可变的? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在逛 programcreek 的時候,發現了一些精妙絕倫的主題。比如說:為什么 Java 字符串是不可變的?像這類靈魂拷問的主題,非常值得深思。對于絕大多數的初級程序員來說,往往停留在“知其然不知其所以然”的層面上——會用,但要說底層的原理,可就只能撓撓頭雙手一攤一張問號臉了。很長一段時間內,我也一直處于這種層面上。導致的局面就是,我在挖一些高深點的技術方案時,往往束手無策;在讀一些高深點的技術文章時,往往理解不了作者在說什么。借此機會,我就和大家一起,對“為什么 Java 字符串是不可變的”進行一次深入地研究。注意了,準備打怪升級了!

01. 圖文分析

來看下面這行代碼。String alita = "阿麗塔";這行代碼在字符串常量池中創建了一個內容為“阿麗塔”的對象,并將其賦值給了字符串變量 alita(存儲的是字符串對象"阿麗塔"的引用)。如下圖所示。再來看下面這行代碼。String wanger = alita;這行代碼將字符串變量 alita 賦值給了字符串變量 wanger。這時候,wanger 和 alita 存儲的是同一個字符串對象的引用。如下圖所示。再來看下面這行代碼。alita = "戰斗天使".concat(alita);這行代碼將字符串“戰斗天使”拼接在字符串變量 alita 的前面,并重新賦值給 alita。這個過程就比之前的復雜了。我們需要先來看看?concat()方法做了什么,源碼如下所示。public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true);}可以看得出,"戰斗天使".concat(alita)這行代碼會先在字符串常量池中創建一個新的字符串對象,內容為“戰斗天使”,然后?concat()方法會將其對應的字符數組和“阿麗塔”對應的字符數組復制到一個新的字符數組 buf 中,最后,再通過 new 關鍵字創建了一個新的字符串對象,并返回。如下圖所示。從上圖中可以得出結論,alita 此時引用的是在堆中新創建的字符串對象。

02. 對象和對象引用

可能有些讀者看完上面的圖文分析沒有理解反而更疑惑了:alita 不是變了嗎?從“阿麗塔”變為“戰斗天使阿麗塔”?怎么還說字符串是不可變的呢?這里需要給大家解釋一下,什么是對象,什么是對象引用。在 Java 中,由于不能直接操作對象本身,所以就有了對象引用這個概念,對象引用存儲的是對象在內存中的地址。PS:Java 虛擬機在執行程序的過程中會把內存區域劃分為若干個不同的數據區域,如下圖所示。對象存儲在堆(heap)中,而對象的引用存儲在棧(stack)中。我們通常所說的“字符串是不可變的”是指“字符串對象是不可變的”。alita 是字符串對象“阿麗塔”或者“戰斗天使阿麗塔”的引用。這下應該明白了吧?

03. 源碼分析

我們來看一下 String 類的部分源碼。public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];}可以看得出, String 類其實是通過操作字符數組 value 實現的。而 value 是 private 的,也沒有提供?serValue()這樣的方法進行修改;況且 value 還是 final 的,意味著 value 一旦被初始化,就無法進行改變。另外呢,String 類提供的方法,比如說?substring():public String substring(int beginIndex) {int subLen = value.length - beginIndex;return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);}toLowerCase():public String toLowerCase(Locale locale) {return new String(result, 0, len + resultOffset);}還有之前提到的?concat(),看似都能改變字符串的內容,但其實都是在方法內部使用 new 關鍵字重新創建的新字符串對象。

04. 為什么要不可變

String 類的源碼中還有一個重要的字段 hash,用來保存字符串對象的 hashCode。public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence { /** Cache the hash code for the string */ private int hash; // Default to 0 public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }}因為字符串是不可變的,所以一旦被創建,它的 hash 值就不會再改變了。由此字符串非常適合作為 HashMap 的 key 值,這樣可以極大地提高效率。另外呢,不可變對象天生是線程安全的,因此字符串可以在多個線程之間共享。舉個反面的例子,假如字符串是可變的,那么數據庫的用戶名和密碼(字符串形式獲得數據庫連接)將不再安全,一些高手可以隨意篡改,從而導致嚴重的安全問題。

05. 最后

總結一下,字符串一旦在內存中被創建,就無法被更改。String 類的所有方法都不會改變字符串本身,而是返回一個新的字符串對象。如果需要一個可修改的字符序列,建議使用 StringBuffer 或 StringBuilder 類代替 String 類,否則每次創建的字新符串對象會導致 Java 虛擬機花費大量的時間進行垃圾回收。參考鏈接:https://www.programcreek.com/2009/02/diagram-to-show-java-strings-immutability

總結

以上是生活随笔為你收集整理的java 字符串赋值_灵魂拷问:为什么 Java 字符串是不可变的?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。