中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Java的String

發布時間:2021-10-14 15:50:49 來源:億速云 閱讀:111 作者:iii 欄目:編程語言

本篇內容介紹了“如何理解Java的String”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1.String的特性

1.1不變性

我們常常聽人說,HashMap 的 key 建議使用不可變類,比如說 String  這種不可變類。這里說不可變指的是類值一旦被初始化,就不能再被改變了,如果被修改,將會是新的類,我們寫個demo 來演示一下。

public class test {       public static void main(String[] args){         String str="hello";         str=str+"world";     } }

從代碼上來看,s 的值好像被修改了,但從 debug 的日志來看,其實是 s 的內存地址已經被修了,也就說 s =“world”  這個看似簡單的賦值,其實已經把 s 的引用指向了新的 String,debug  截圖顯示內存地址已經被修改,兩張截圖如下,我們可以看到標紅的地址值已經修改了。

如何理解Java的String

如何理解Java的String

用示意圖來表示堆內存,即見下圖。

如何理解Java的String

我們可以看下str的地址已經改了,說了生成了兩個字符串,String類的官方注釋為Strings are constant; their values  cannot be changed after they are created. 簡單翻譯下為字符串是常量;它們的值在創建后不能更改。

下面為String的相關代碼,如下代碼,我們可以看到:

1. String 被 final 修飾,說明 String 類絕不可能被繼承了,也就是說任何對 String  的操作方法,都不會被繼承覆寫,即可保證雙親委派機制,保證基類的安全性。

2. String 中保存數據的是一個 char 的數組 value。我們發現 value 也是被 final 修飾的,也就是說 value  一旦被賦值,內存地址是絕對無法修改的,而且 value 的權限是 private 的,外部絕對訪問不到,String沒有開放出可以對 value  進行賦值的方法,所以說 value 一旦產生,內存地址就根本無法被修改。

//char類型的final數組     private final char value[];              //hash值     private int hash;       private static final long serialVersionUID = -6849794470754667710L;

1.2相等判斷

相等判斷邏輯寫的很清楚明了,如果有人問如何判斷兩者是否相等時,我們可以從兩者的底層結構出發,這樣可以迅速想到一種貼合實際的思路和方法,就像 String  底層的數據結構是 char 的數組一樣,判斷相等時,就挨個比較 char 數組中的字符是否相等即可。(這里先挖個坑,攜程問過類似題目)

public boolean equals(Object anObject) {                      //如果地址相等,則直接返回true        if (this == anObject) {                    return true;         }               //如果為String字符串,則進行下面的邏輯判斷         if (anObject instanceof String) {                     //將對象轉化為String             String anotherString = (String)anObject;                   //獲取當前值的長度             int n = value.length;                         //先比較長度是否相等,如果長度不相等,這兩個肯定不相等             if (n == anotherString.value.length) {                                 char v1[] = value;                                char v2[] = anotherString.value;                int i = 0;                //while循環挨個比較每個char                     while (n-- != 0) {                                         if (v1[i] != v2[i])                                             return false;                         i++;                     }                             return true;             }         }                 return false;     }

相等邏輯的流程圖如下,我們可以看到整個流程還是很清楚的。

如何理解Java的String

1.3替換操作

替換在平時工作中也經常使用,主要有 replace 替換所有字符、replaceAll 批量替換字符串、replaceFirst這三種場景。

下面寫了一個 demo 演示一下三種場景:

public static void main(String[] args) {         String str = "hello word !!";         System.out.println("替換之前 :" + str);         str = str.replace('l', 'd');         System.out.println("替換所有字符 :" + str);         str = str.replaceAll("d", "l");         System.out.println("替換全部 :" + str);         str = str.replaceFirst("l", "");         System.out.println("替換第一個 l :" + str);     }

輸出的結果是:

如何理解Java的String

這邊要注意一點是replace和replaceAll的區別,不是替換和替換所有的區別哦。

而是replaceAll支持正則表達式,因此會對參數進行解析(兩個參數均是),如replaceAll("\\d",  "*"),而replace則不會,replace("\\d","*")就是替換"\\d"的字符串,而不會解析為正則。

1.4 intern方法

String.intern() 是一個 Native 方法,即是c和c++與底層交互的代碼,它的作用(在JDK1.6和1.7操作不同)是:

如果運行時常量池中已經包含一個等于此 String 對象內容的字符串,則直接返回常量池中該字符串的引用;

如果沒有, 那么在jdk1.6中,將此String對象添加到常量池中,然后返回這個String對象的引用(此時引用的串在常量池)。

在jdk1.7中,放入一個引用,指向堆中的String對象的地址,返回這個引用地址(此時引用的串在堆)。

public native String intern();

如果看上面看不懂,我們來看下一下具體的例子,并來分析下。

public static void main(String[] args) {         String s1 = new String("學習Java的小姐姐");         s1.intern();         String s2 = "學習Java的小姐姐";         System.out.println(s1 == s2);          String s3 = new String("學習Java的小姐姐") + new String("test");         s3.intern();         String s4 = "學習Java的小姐姐test";         System.out.println(s3 == s4);      }

我們來看下結果,實際的打印信息如下。

如何理解Java的String

為什么顯示這樣的結果,我們來看下。所以在 jdk7 的版本中,字符串常量池已經從方法區移到正常的堆 區域了。

  • 第一個false: 第一句代碼String s1 = new String("學習Java的小姐姐");生成了2個對象。常量池中的“學習Java的小姐姐”  和堆中的字符串對象。s1.intern(); 這一句是 s1 對象去常量池中尋找后,發現 “學習Java的小姐姐” 已經在常量池里了。接下來String s2  = "學習Java的小姐姐"; 這句代碼是生成一個 s2的引用指向常量池中的“學習Java的小姐姐”對象。結果就是 s 和 s2  的引用地址明顯不同,所以打印結果是false。

  • 第二個true:先看 s3和s4字符串。String s3 = new String("學習Java的小姐姐") + new  String("test");,這句代碼中現在生成了3個對象,是字符串常量池中的“學習Java的小姐姐” ,"test"和堆 中的  s3引用指向的對象。此時s3引用對象內容是”學習Java的小姐姐test”,但此時常量池中是沒有  “學習Java的小姐姐test”對象的,接下來s3.intern();這一句代碼,是將 s3中的“學習Java的小姐姐test”字符串放入 String  常量池中,因為此時常量池中不存在“學習Java的小姐姐test”字符串,常量池不需要再存儲一份對象了,可以直接存儲堆中的引用。這份引用指向 s3  引用的對象。也就是說引用地址是相同的。最后String s4 = "學習Java的小姐姐test";  這句代碼中”學習Java的小姐姐test”是顯示聲明的,因此會直接去常量池中創建,創建的時候發現已經有這個對象了,此時也就是指向 s3 引用對象的一個引用。所以  s4 引用就指向和 s3 一樣了。因此最后的比較 s3 == s4 是 true。

如何理解Java的String

我們再看下,如果把上面的兩行代碼調整下位置,打印結果是不是不同。

public static void main(String[] args) {         String s1 = new String("學習Java的小姐姐");         String s2 = "學習Java的小姐姐";         s1.intern();         System.out.println(s1 == s2);          String s3 = new String("學習Java的小姐姐") + new String("test");         String s4 = "學習Java的小姐姐test";         s3.intern();         System.out.println(s3 == s4);      }

如何理解Java的String

  • 第一個false: s1 和 s2 代碼中,s1.intern();,這一句往后放也不會有什么影響了,因為對象池中在執行第一句代碼String s =  new String("學習Java的小姐姐");的時候已經生成“學習Java的小姐姐”對象了。下邊的s2聲明都是直接從常量池中取地址引用的。s 和 s2  的引用地址是不會相等的。

  • 第二個false:與上面唯一的區別在于 s3.intern(); 的順序是放在String s4 =  "學習Java的小姐姐test";后了。這樣,首先執行String s4 = "學習Java的小姐姐test";聲明 s4  的時候常量池中是不存在“學習Java的小姐姐test”對象的,執行完畢后,“學習Java的小姐姐test“對象是 s4  聲明產生的新對象。然后再執行s3.intern();時,常量池中“學習Java的小姐姐test”對象已經存在了,因此 s3 和 s4 的引用是不同的。

2. String、StringBuilder和StringBuffer

2.1 繼承結構

如何理解Java的String

2.2 主要區別

1)String是不可變字符序列,StringBuilder和StringBuffer是可變字符序列。

2)執行速度StringBuilder > StringBuffer > String。

3)StringBuilder是非線程安全的,StringBuffer是線程安全的。

“如何理解Java的String”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

乐亭县| 新丰县| 永嘉县| 德昌县| 锦州市| 安阳县| 台山市| 浏阳市| 昌邑市| 湟中县| 潜山县| 方山县| 永寿县| 江华| 揭东县| 周宁县| 虎林市| 肥西县| 南投县| 巫山县| 黄浦区| 镇雄县| 鄢陵县| 施甸县| 项城市| 广水市| 庆阳市| 宜阳县| 白水县| 邯郸县| 文安县| 东宁县| 公主岭市| 永春县| 阿巴嘎旗| 肥城市| 灵丘县| 白玉县| 濮阳县| 古浪县| 当涂县|