您好,登錄后才能下訂單哦!
為什么Java中String類設置完不能改?可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
String就是java等編程語言中的字符串,用雙引號引起來的幾個字符.如"Abc","一天".與字符不同的是它指的是一串字符或者一類標識符。String類是不可變(final)的,對String類的任何改變,都是返回一個新的String類對象.這樣的話把String類的引用傳遞給一個方法,該方法對String的任何改變,對原引用指向的對象沒有任何影響,這一點和基本數據類型相似。
Java中String類示例:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];}
String類的值是保存在value數組中的,并且是被private final修飾的
1、private修飾,表明外部的類是訪問不到value的,同時子類也訪問不到,當然String類不可能有子類,因為類被final修飾了
2、final修飾,表明value的引用是不會被改變的,而value只會在String的構造函數中被初始化,而且并沒有其他方法可以修改value數組中的值,保證了value的引用和值都不會發生變化
所以我們說String類是不可變的。
而很多方法,如substring并不是在原來的String類上進行操作,而是生成了新的String類
public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = value.length - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);}
字符串常量池
Java有8種基本數據類型
整數類型:byte,short,int,long。包裝類型為Byte,Short,Integer,Long
浮點類型:float、double。包裝類型為Float,Double
字符類型:char。包裝類型為Character
布爾類型:boolean。包裝類型為Boolean
8種包裝類型中除了Float,Double沒有實現常量池,剩下的都實現了,當然都是通過享元模式實現的
String類的常量池是在JVM層面實現的。
為什么要有常量池?
常量池是為了避免頻繁的創建和銷毀對象而影響系統性能,其實現了對象的共享。
例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中。
節省內存空間:常量池中所有相同的字符串常量被合并,只占用一個空間。
節省運行時間:比較字符串時,== 比equals()快。對于兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等。
字符串常量池放在哪?
jdk1.7之前的不討論,從jdk1.7開始,字符串常量池就開始放在堆中,然后本文的所有內容都是基于jdk1.8的
下面這個代碼還是經常被問到的
String str1 = "abc"; String str2 = "abc"; String str3 = new String("abc"); String str4 = new String("abc"); // trueSystem.out.println(str1 == str2); // falseSystem.out.println(str1 == str3); // falseSystem.out.println(str3 == str4);
內存中的結構如下
其中常量池中存的是引用
解釋一下上面代碼的輸出,Java中有2種創建字符串對象的方式
String str1 = "abc"; String str2 = "abc"; // trueSystem.out.println(str1 == str2);
采用字面值的方式創建一個字符串時,JVM首先會去字符串池中查找是否存在"abc"這個對象
如果不存在,則在字符串池中創建"abc"這個對象,然后將池中"abc"這個對象的地址賦給str1,這樣str1會指向池中"abc"這個字符串對象
如果存在,則不創建任何對象,直接將池中"abc"這個對象的地址返回,賦給str2。因為str1、str2指向同一個字符串池中的"abc"對象,所以結果為true。
String str3 = new String("abc"); String str4 = new String("abc"); // falseSystem.out.println(str3 == str4);
采用new關鍵字新建一個字符串對象時,JVM首先在字符串池中查找有沒有"abc"這個字符串對象,
如果沒有,則首先在字符串池中創建一個"abc"字符串對象,然后再在堆中創建一個"abc"字符串對象,然后將堆中這個"abc"字符串對象的地址賦給str3
如果有,則不在池中再去創建"abc"這個對象了,直接在堆中創建一個"abc"字符串對象,然后將堆中的這個"abc"對象的地址賦給str4。這樣,str4就指向了堆中創建的這個"abc"字符串對象;
因為str3和str4指向的是不同的字符串對象,結果為false。
緩存HashCode
String類在被創建的時候,hashcode就被緩存到hash成員變量中,因為String類是不可變的,所以hashcode是不會改變的。這樣每次想使用hashcode的時候直接取就行了,而不用重新計算,提高了效率
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** Cache the hash code for the string */ private int hash; // Default to 0 }
可以用作HashMap的key
由于String類不可變的特性,所以經常被用作HashMap的key,如果String類是可變的,內容改變,hashCode也會改變,當根據這個key從HashMap中取的時候有可能取不到value,或者取到錯的value
線程安全
不可變對象天生就是線程安全的,這樣可以避免在多線程環境下對String做同步操作。
看完上述內容,你們對Java中String類有進一步的了解嗎?如果還想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。