Java String對(duì)象使用方法詳解
Java String對(duì)象使用方法詳解
先來(lái)看一個(gè)例子,代碼如下:
public class Test { public static void main(String[] args) { String str = "abc"; String str1 = "abc"; String str2 = new String("abc"); System.out.println(str == str1); System.out.println(str1 == "abc"); System.out.println(str2 == "abc"); System.out.println(str1 == str2); System.out.println(str1.equals(str2)); System.out.println(str1 == str2.intern()); System.out.println(str2 == str2.intern()); System.out.println(str1.hashCode() == str2.hashCode()); } }
如果您能對(duì)這8個(gè)輸出結(jié)果直接判斷出來(lái),下面的分析就不用看了。但是我想還是有很多人對(duì)這個(gè)String對(duì)象這個(gè)問(wèn)題只是表面的理解,下面就來(lái)分析一下Java語(yǔ)言String類和對(duì)象及其運(yùn)行機(jī)制的問(wèn)題。
做個(gè)基礎(chǔ)的說(shuō)明,堆(heap)內(nèi)存和棧(Stack)內(nèi)存的問(wèn)題。堆和棧的數(shù)據(jù)結(jié)構(gòu)這里就不解釋了。Java語(yǔ)言使用內(nèi)存的時(shí)候,棧內(nèi)存主要保存以下內(nèi)容:基本數(shù)據(jù)類型和對(duì)象的引用,而堆內(nèi)存存儲(chǔ)對(duì)象,棧內(nèi)存的速度要快于堆內(nèi)存??偨Y(jié)成一句話就是:引用在棧而對(duì)象在堆。
Java中的比較有兩種,是==和equals()方法,equals()是Object類的方法,定義在Object類中的equals()方法是如下實(shí)現(xiàn)的:
public boolean equals(Object obj){ return (this==obj); }
String類重寫(xiě)了equals()方法,改變了這些類型對(duì)象相等的原則,即判斷對(duì)象是否相等依據(jù)的原則為判斷二者的內(nèi)容是否相等。
了解以上內(nèi)容后我們來(lái)說(shuō)說(shuō)String,String類的本質(zhì)是字符數(shù)組char[],其次String類是final的,是不可被繼承的,這點(diǎn)可能被大多數(shù)人忽略,再次String是特殊的封裝類型,使用String時(shí)可以直接賦值,也可以用new來(lái)創(chuàng)建對(duì)象,但是這二者的實(shí)現(xiàn)機(jī)制是不同的。還有一個(gè)String池的概念,Java運(yùn)行時(shí)維護(hù)一個(gè)String池,池中的String對(duì)象不可重復(fù),沒(méi)有創(chuàng)建,有則作罷。String池不屬于堆和棧,而是屬于常量池。下面分析上方代碼的真正含義
String str = "abc"; String str1= "abc";
第一句的真正含義是在String池中創(chuàng)建一個(gè)對(duì)象”abc”,然后引用時(shí)str指向池中的對(duì)象”abc”。第二句執(zhí)行時(shí),因?yàn)椤盿bc”已經(jīng)存在于String池了,所以不再創(chuàng)建,則str==str1返回true就明白了。str1==”abc”肯定正確了,在String池中只有一個(gè)”abc”,而str和str1都指向池中的”abc”,就是這個(gè)道理。
String str2 = new String("abc");
這個(gè)是Java SE的熱點(diǎn)問(wèn)題,眾所周知,單獨(dú)這句話創(chuàng)建了2個(gè)String對(duì)象,而基于上面兩句,只在棧內(nèi)存創(chuàng)建str2引用,在堆內(nèi)存上創(chuàng)建一個(gè)String對(duì)象,內(nèi)容是”abc”,而str2指向堆內(nèi)存對(duì)象的首地址。
下面就是str2==”abc”的問(wèn)題了,顯然不對(duì),”abc”是位于String池中的對(duì)象,而str2指向的是堆內(nèi)存的String對(duì)象,==判斷的是地址,肯定不等了。
str1.equals(str2),這個(gè)是對(duì)的,前面說(shuō)過(guò),String類的equals重寫(xiě)了Object類的equals()方法,實(shí)際就是判斷內(nèi)容是否相同了。
下面說(shuō)下intern()方法,在JavaDoc文檔中,這樣描述了intern()方法:返回字符串對(duì)象的規(guī)范化表示形式。怎么理解這句話?實(shí)際上過(guò)程是這樣進(jìn)行的:該方法現(xiàn)在String池中查找是否存在一個(gè)對(duì)象,存在了就返回String池中對(duì)象的引用。
那么本例中String池存在”abc”,則調(diào)用intern()方法時(shí)返回的是池中”abc”對(duì)象引用,那么和str/str1都是等同的,和str2就不同了,因?yàn)閟tr2指向的是堆內(nèi)存。
hashCode()方法是返回字符串內(nèi)容的哈希碼,既然內(nèi)容相同,哈希碼必然相同,那他們就相等了,這個(gè)容易理解。
再看下面的例子:
public class Test { private static String str = "abc"; public static void main(String[] args) { String str1 = "a"; String str2 = "bc"; String combo = str1 + str2; System.out.println(str == combo); System.out.println(str == combo.intern()); } }
這個(gè)例子用來(lái)說(shuō)明用+連接字符串時(shí),實(shí)際上是在堆內(nèi)容創(chuàng)建對(duì)象,那么combo指向的是堆內(nèi)存存儲(chǔ)”abc”字符串的空間首地址,顯然str==combo是錯(cuò)誤的,而str==combo.intern()是正確的,在String池中也存在”abc”,那就直接返回了,而str也是指向String池中的”abc”對(duì)象的。此例說(shuō)明任何重新修改String都是重新分配內(nèi)存空間,這就使得String對(duì)象之間互不干擾。也就是String中的內(nèi)容一旦生成不可改變,直至生成新的對(duì)象。
同時(shí)問(wèn)題也來(lái)了,使用+連接字符串每次都生成新的對(duì)象,而且是在堆內(nèi)存上進(jìn)行,而堆內(nèi)存速度比較慢(相對(duì)而言),那么再大量連接字符串時(shí)直接+是不可取的,當(dāng)然需要一種效率高的方法。Java提供的StringBuffer和StringBuilder就是解決這個(gè)問(wèn)題的。區(qū)別是前者是線程安全的而后者是非線程安全的,StringBuilder在JDK1.5之后才有。不保證安全的StringBuilder有比StringBuffer更高的效率。
自JDK1.5之后,Java虛擬機(jī)執(zhí)行字符串的+操作時(shí),內(nèi)部實(shí)現(xiàn)也是StringBuilder,之前采用StringBuffer實(shí)現(xiàn)。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- java中的 toString()方法實(shí)例代碼
- Java String 和StringBuffer的詳解及區(qū)別
- Java中Object toString方法簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- java 中InputStream,String,File之間的相互轉(zhuǎn)化對(duì)比
- Java 中 String,StringBuffer 和 StringBuilder 的區(qū)別及用法
- JAVA String轉(zhuǎn)化成java.sql.date和java.sql.time方法示例
- java 中 String format 和Math類實(shí)例詳解
相關(guān)文章
如何使用JWT的SpringSecurity實(shí)現(xiàn)前后端分離
這篇文章主要介紹了使用JWT的SpringSecurity實(shí)現(xiàn)前后端分離,登錄成功需要返回json數(shù)據(jù)登錄失敗需要返回json數(shù)據(jù)權(quán)限不足時(shí)返回json數(shù)據(jù)未登錄訪問(wèn)資源返回json數(shù)據(jù),需要的朋友可以參考下2024-08-08java編程實(shí)現(xiàn)楊輝三角兩種輸出結(jié)果實(shí)例代碼
這篇文章主要介紹了java編程實(shí)現(xiàn)楊輝三角兩種輸出結(jié)果實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12SpringBoot中創(chuàng)建bean的7種方式總結(jié)
Spring是一款廣泛應(yīng)用于企業(yè)級(jí)應(yīng)用程序開(kāi)發(fā)的Java框架,其 IOC 和 DI 特性可以有效地管理應(yīng)用程序中的對(duì)象,提高了應(yīng)用程序的可維護(hù)性和可擴(kuò)展性,那你知道spring有哪些方式將bean放入容器嘛,今天就給大家總結(jié)一下2023-07-07解決idea2020.1 用gitee push推送被拒絕的原因(親測(cè)有效)
這篇文章主要介紹了解決idea2020.1 用gitee push推送被拒絕的原因(親測(cè)有效),本文給大家分享解決方案,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08IntelliJ IDEA中如何構(gòu)建Spring Boot的項(xiàng)目
這篇文章主要介紹了IntelliJ IDEA中如何構(gòu)建Spring Boot的項(xiàng)目問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07