為什么Java中String類(lèi)設(shè)置完不能改?可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
創(chuàng)新互聯(lián)是專(zhuān)業(yè)的鶴崗網(wǎng)站建設(shè)公司,鶴崗接單;提供網(wǎng)站制作、成都網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行鶴崗網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
String就是java等編程語(yǔ)言中的字符串,用雙引號(hào)引起來(lái)的幾個(gè)字符.如"Abc","一天".與字符不同的是它指的是一串字符或者一類(lèi)標(biāo)識(shí)符。String類(lèi)是不可變(final)的,對(duì)String類(lèi)的任何改變,都是返回一個(gè)新的String類(lèi)對(duì)象.這樣的話把String類(lèi)的引用傳遞給一個(gè)方法,該方法對(duì)String的任何改變,對(duì)原引用指向的對(duì)象沒(méi)有任何影響,這一點(diǎn)和基本數(shù)據(jù)類(lèi)型相似。
Java中String類(lèi)示例:
public final class String implements java.io.Serializable, Comparable, CharSequence { /** The value is used for character storage. */ private final char value[];}
String類(lèi)的值是保存在value數(shù)組中的,并且是被private final修飾的
1、private修飾,表明外部的類(lèi)是訪問(wèn)不到value的,同時(shí)子類(lèi)也訪問(wèn)不到,當(dāng)然String類(lèi)不可能有子類(lèi),因?yàn)轭?lèi)被final修飾了
2、final修飾,表明value的引用是不會(huì)被改變的,而value只會(huì)在String的構(gòu)造函數(shù)中被初始化,而且并沒(méi)有其他方法可以修改value數(shù)組中的值,保證了value的引用和值都不會(huì)發(fā)生變化
所以我們說(shuō)String類(lèi)是不可變的。
而很多方法,如substring并不是在原來(lái)的String類(lèi)上進(jìn)行操作,而是生成了新的String類(lèi)
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種基本數(shù)據(jù)類(lèi)型
整數(shù)類(lèi)型:byte,short,int,long。包裝類(lèi)型為Byte,Short,Integer,Long
浮點(diǎn)類(lèi)型:float、double。包裝類(lèi)型為Float,Double
字符類(lèi)型:char。包裝類(lèi)型為Character
布爾類(lèi)型:boolean。包裝類(lèi)型為Boolean
8種包裝類(lèi)型中除了Float,Double沒(méi)有實(shí)現(xiàn)常量池,剩下的都實(shí)現(xiàn)了,當(dāng)然都是通過(guò)享元模式實(shí)現(xiàn)的
String類(lèi)的常量池是在JVM層面實(shí)現(xiàn)的。
為什么要有常量池?
常量池是為了避免頻繁的創(chuàng)建和銷(xiāo)毀對(duì)象而影響系統(tǒng)性能,其實(shí)現(xiàn)了對(duì)象的共享。
例如字符串常量池,在編譯階段就把所有的字符串文字放到一個(gè)常量池中。
節(jié)省內(nèi)存空間:常量池中所有相同的字符串常量被合并,只占用一個(gè)空間。
節(jié)省運(yùn)行時(shí)間:比較字符串時(shí),== 比equals()快。對(duì)于兩個(gè)引用變量,只用==判斷引用是否相等,也就可以判斷實(shí)際值是否相等。
字符串常量池放在哪?
jdk1.7之前的不討論,從jdk1.7開(kāi)始,字符串常量池就開(kāi)始放在堆中,然后本文的所有內(nèi)容都是基于jdk1.8的
下面這個(gè)代碼還是經(jīng)常被問(wèn)到的
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);
內(nèi)存中的結(jié)構(gòu)如下
其中常量池中存的是引用
解釋一下上面代碼的輸出,Java中有2種創(chuàng)建字符串對(duì)象的方式
String str1 = "abc"; String str2 = "abc"; // trueSystem.out.println(str1 == str2);
采用字面值的方式創(chuàng)建一個(gè)字符串時(shí),JVM首先會(huì)去字符串池中查找是否存在"abc"這個(gè)對(duì)象
如果不存在,則在字符串池中創(chuàng)建"abc"這個(gè)對(duì)象,然后將池中"abc"這個(gè)對(duì)象的地址賦給str1,這樣str1會(huì)指向池中"abc"這個(gè)字符串對(duì)象
如果存在,則不創(chuàng)建任何對(duì)象,直接將池中"abc"這個(gè)對(duì)象的地址返回,賦給str2。因?yàn)閟tr1、str2指向同一個(gè)字符串池中的"abc"對(duì)象,所以結(jié)果為true。
String str3 = new String("abc"); String str4 = new String("abc"); // falseSystem.out.println(str3 == str4);
采用new關(guān)鍵字新建一個(gè)字符串對(duì)象時(shí),JVM首先在字符串池中查找有沒(méi)有"abc"這個(gè)字符串對(duì)象,
如果沒(méi)有,則首先在字符串池中創(chuàng)建一個(gè)"abc"字符串對(duì)象,然后再在堆中創(chuàng)建一個(gè)"abc"字符串對(duì)象,然后將堆中這個(gè)"abc"字符串對(duì)象的地址賦給str3
如果有,則不在池中再去創(chuàng)建"abc"這個(gè)對(duì)象了,直接在堆中創(chuàng)建一個(gè)"abc"字符串對(duì)象,然后將堆中的這個(gè)"abc"對(duì)象的地址賦給str4。這樣,str4就指向了堆中創(chuàng)建的這個(gè)"abc"字符串對(duì)象;
因?yàn)閟tr3和str4指向的是不同的字符串對(duì)象,結(jié)果為false。
緩存HashCode
String類(lèi)在被創(chuàng)建的時(shí)候,hashcode就被緩存到hash成員變量中,因?yàn)镾tring類(lèi)是不可變的,所以hashcode是不會(huì)改變的。這樣每次想使用hashcode的時(shí)候直接取就行了,而不用重新計(jì)算,提高了效率
public final class String implements java.io.Serializable, Comparable, CharSequence { /** Cache the hash code for the string */ private int hash; // Default to 0 }
可以用作HashMap的key
由于String類(lèi)不可變的特性,所以經(jīng)常被用作HashMap的key,如果String類(lèi)是可變的,內(nèi)容改變,hashCode也會(huì)改變,當(dāng)根據(jù)這個(gè)key從HashMap中取的時(shí)候有可能取不到value,或者取到錯(cuò)的value
線程安全
不可變對(duì)象天生就是線程安全的,這樣可以避免在多線程環(huán)境下對(duì)String做同步操作。
看完上述內(nèi)容,你們對(duì)Java中String類(lèi)有進(jìn)一步的了解嗎?如果還想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀。