java中String相等问题
?
判斷兩個(gè)字符串是否相等的問題。在編程中,通常比較兩個(gè)字符串是否相同的表達(dá)式是“==”,但在java中不能這么寫。在java中,用的是equals();
例:A字符串和B和字符串比較:
if(A.equals(B)){
}
返回true?或false.
String?的equals?方法用于比較兩個(gè)字符串是否相等。由于字符串是對(duì)象類型,所以不能用簡(jiǎn)單的“==”判斷。而使用equals比較兩個(gè)對(duì)象的內(nèi)容是否相等。
注意:
equals()比較的是對(duì)象的內(nèi)容(區(qū)分字母的大小寫格式),但是如果使用“==”比較兩個(gè)對(duì)象時(shí),比較的是兩個(gè)對(duì)象的內(nèi)存地址,所以不相等。即使它們內(nèi)容相等,但是不同對(duì)象的內(nèi)存地址也是不相同的。
?
(轉(zhuǎn)載)Java?中String?的相等比較
轉(zhuǎn)載▼
轉(zhuǎn)載 地址:http://wenku.baidu.com/view/d223a71714791711cc791737.html
1.首先介紹三個(gè)String對(duì)象比較的方法:
(1)equals:比較兩個(gè)String對(duì)象的值是否相等。例如:
String str1 = "hello quanjizhu";
String str2 =str1+"haha";
String str3 = new String("hello quanjizhu");
System.out.println(str1.equals(str2)); //false
System.out.println(str1.equals(str3)); //true
(2)= =:比較兩個(gè)String對(duì)象的指向的內(nèi)存地址是否相等。例如:
String str1 = "hello quanjizhu";
String str2 =str1+"haha";
String str3 = new String("hello quanjizhu");
System.out.println(str1==str2);??
System.out.println(str1==str3);?
輸出結(jié)果都為false。
3.原理
要理解 java中String的運(yùn)作方式,必須明確一點(diǎn):String是一個(gè)非可變類(immutable)。什么是非可變類呢?簡(jiǎn)單說來,非可變類的實(shí)例是不能被修改的,每個(gè)實(shí)例中包含的信息都必須在該實(shí)例創(chuàng)建的時(shí)候就提供出來,并且在對(duì)象的整個(gè)生存周期內(nèi)固定不變。java為什么要把String設(shè)計(jì)為非可變類呢?你可以問問 james Gosling :)。但是非可變類確實(shí)有著自身的優(yōu)勢(shì),如狀態(tài)單一,對(duì)象簡(jiǎn)單,便于維護(hù)。其次,該類對(duì)象對(duì)象本質(zhì)上是線程安全的,不要求同步。此外用戶可以共享非可變對(duì)象,甚至可以共享它們的內(nèi)部信息。(詳見 《Effective java》item 13)。String類在java中被大量運(yùn)用,甚至在class文件中都有其身影,因此將其設(shè)計(jì)為簡(jiǎn)單輕便的非可變類是比較合適的。
(1)創(chuàng)建。
????好了,知道String是非可變類以后,我們可以進(jìn)一步了解String的構(gòu)造方式了。創(chuàng)建一個(gè)Stirng對(duì)象,主要就有以下兩種方式:
java 代碼
String str1 = new String("abc");???
Stirng str2 = "abc";?
?????雖然兩個(gè)語句都是返回一個(gè)String對(duì)象的引用,但是jvm對(duì)兩者的處理方式是不一樣的。對(duì)于第一種,jvm會(huì)馬上在heap中創(chuàng)建一個(gè)String對(duì)象,然后將該對(duì)象的引用返回給用戶。對(duì)于第二種,jvm首先會(huì)在內(nèi)部維護(hù)的strings pool中通過String的 equels 方法查找是對(duì)象池中是否存放有該String對(duì)象,如果有,則返回已有的String對(duì)象給用戶,而不會(huì)在heap中重新創(chuàng)建一個(gè)新的String對(duì)象;如果對(duì)象池中沒有該String對(duì)象,jvm則在heap中創(chuàng)建新的String對(duì)象,將其引用返回給用戶,同時(shí)將該引用添加至strings pool中。注意:使用第一種方法創(chuàng)建對(duì)象時(shí),jvm是不會(huì)主動(dòng)把該對(duì)象放到strings pool里面的,除非程序調(diào)用 String的intern方法。看下面的例子:
java 代碼
String str1 = new String("abc"); //jvm 在堆上創(chuàng)建一個(gè)String對(duì)象??
?
?//jvm 在strings pool中找不到值為“abc”的字符串,因此??
?//在堆上創(chuàng)建一個(gè)String對(duì)象,并將該對(duì)象的引用加入至strings pool中??
?//此時(shí)堆上有兩個(gè)String對(duì)象??
Stirng str2 = "abc";??
?
?if(str1 == str2){??
?????????System.out.println("str1 == str2");??
?}else{??
?????????System.out.println("str1 != str2");??
??//打印結(jié)果是 str1 != str2,因?yàn)樗鼈兪嵌焉蟽蓚€(gè)不同的對(duì)象??
?
??String str3 = "abc";??
?//此時(shí),jvm發(fā)現(xiàn)strings pool中已有“abc”對(duì)象了,因?yàn)椤癮bc”equels “abc”??
?//因此直接返回str2指向的對(duì)象給str3,也就是說str2和str3是指向同一個(gè)對(duì)象的引用??
??if(str2 == str3){??
?????????System.out.println("str2 == str3");??
??}else{??
?????????System.out.println("str2 != str3");??
??}??
?//打印結(jié)果為 str2 == str3?
???再看下面的例子:
java 代碼
String str1 = new String("abc"); //jvm 在堆上創(chuàng)建一個(gè)String對(duì)象??
?
str1 = str1.intern();??
//程序顯式將str1放到strings pool中,intern運(yùn)行過程是這樣的:首先查看strings pool??
//有沒“abc”對(duì)象的引用,沒有,則在堆中新建一個(gè)對(duì)象,然后將新對(duì)象的引用加入至??
//strings pool中。執(zhí)行完該語句后,str1原來指向的String對(duì)象已經(jīng)成為垃圾對(duì)象了,隨時(shí)會(huì)??
//被GC收集。??
?
//此時(shí),jvm發(fā)現(xiàn)strings pool中已有“abc”對(duì)象了,因?yàn)椤癮bc”equels “abc”??
//因此直接返回str1指向的對(duì)象給str2,也就是說str2和str1引用著同一個(gè)對(duì)象,??
//此時(shí),堆上的有效對(duì)象只有一個(gè)。??
Stirng str2 = "abc";??
?
?if(str1 == str2){??
?????????System.out.println("str1 == str2");??
?}else{??
?????????System.out.println("str1 != str2");??
?}??
??//打印結(jié)果是 str1 == str2??
?
為什么jvm可以這樣處理String對(duì)象呢?就是因?yàn)镾tring的非可變性。既然所引用的對(duì)象一旦創(chuàng)建就永不更改,那么多個(gè)引用共用一個(gè)對(duì)象時(shí)互不影響。
(2)串接(Concatenation)。
?????java程序員應(yīng)該都知道濫用String的串接操作符是會(huì)影響程序的性能的。性能問題從何而來呢?歸根結(jié)底就是String類的非可變性。既然String對(duì)象都是非可變的,也就是對(duì)象一旦創(chuàng)建了就不能夠改變其內(nèi)在狀態(tài)了,但是串接操作明顯是要增長(zhǎng)字符串的,也就是要改變String的內(nèi)部狀態(tài),兩者出現(xiàn)了矛盾。怎么辦呢?要維護(hù)String的非可變性,只好在串接完成后新建一個(gè)String 對(duì)象來表示新產(chǎn)生的字符串了。也就是說,每一次執(zhí)行串接操作都會(huì)導(dǎo)致新對(duì)象的產(chǎn)生,如果串接操作執(zhí)行很頻繁,就會(huì)導(dǎo)致大量對(duì)象的創(chuàng)建,性能問題也就隨之而來了。
????為了解決這個(gè)問題,jdk為String類提供了一個(gè)可變的配套類,StringBuffer。使用StringBuffer對(duì)象,由于該類是可變的,串接時(shí)僅僅時(shí)改變了內(nèi)部數(shù)據(jù)結(jié)構(gòu),而不會(huì)創(chuàng)建新的對(duì)象,因此性能上有很大的提高。針對(duì)單線程,jdk 5.0還提供了StringBuilder類,在單線程環(huán)境下,由于不用考慮同步問題,使用該類使性能得到進(jìn)一步的提高。
(3)String的長(zhǎng)度
???我們可以使用串接操作符得到一個(gè)長(zhǎng)度更長(zhǎng)的字符串,那么,String對(duì)象最多能容納多少字符呢?查看String的源代碼我們可以得知類String中是使用域 count 來記錄對(duì)象字符的數(shù)量,而count 的類型為 int,因此,我們可以推測(cè)最長(zhǎng)的長(zhǎng)度為 2^32,也就是4G。
????不過,我們?cè)诰帉懺创a的時(shí)候,如果使用 Sting str = "aaaa";的形式定義一個(gè)字符串,那么雙引號(hào)里面的ASCII字符最多只能有 65534 個(gè)。為什么呢?因?yàn)樵赾lass文件的規(guī)范中, CONSTANT_Utf8_info表中使用一個(gè)16位的無符號(hào)整數(shù)來記錄字符串的長(zhǎng)度的,最多能表示 65536個(gè)字節(jié),而java class 文件是使用一種變體UTF-8格式來存放字符的,null值使用兩個(gè)字節(jié)來表示,因此只剩下 65536- 2 = 65534個(gè)字節(jié)。也正是變體UTF-8的原因,如果字符串中含有中文等非ASCII字符,那么雙引號(hào)中字符的數(shù)量會(huì)更少(一個(gè)中文字符占用三個(gè)字節(jié))。如果超出這個(gè)數(shù)量,在編譯的時(shí)候編譯器會(huì)報(bào)錯(cuò)。
(3)compareTo:比較兩個(gè)String對(duì)象的值是否相等。例如:
String str1 = "hello quanjizhu";
String str2 =str1+"haha";
String str3 = new String("hello quanjizhu");
System.out.println(str1.compareTo(str2));?
System.out.println(str1.compareTo(str3));?
輸出結(jié)果都為0。(若輸出結(jié)果大于0表示str1大于str2)
2.String類的幾種初始化方法的區(qū)別
(1) String str1 = "hello quanjizhu";
首先到String pool中查找有沒有值為hello quanjizhu的對(duì)象,若有則讓str1直接指向此內(nèi)存地址;若沒有則在內(nèi)存堆中重新開辟空間給str1,并把hello quanjizhu加到String pool中。
(2)String str3 = new String("hello quanjizhu");
每次初始化都會(huì)重新在內(nèi)存堆中開辟空間給新的對(duì)象,而不會(huì)到String pool中查找,更不會(huì)添加到String pool中。除非顯示的調(diào)用intern方法。
str3.interl();這時(shí)就會(huì)把hello quanjizhu加到String pool中。
(3)
String str1 = "hello quanjizhu";
String str2 ="hello" +"quanjizhu";
?String str3 ="hello "+"quanjizhu";在編譯的時(shí)候會(huì)優(yōu)化成String str3 = "hello quanjizhu";所有str1和str2指向的是同一內(nèi)存地址。
(4)
String var = “quanjizhu“;
String str4 = “hello “+var;
??System.out.println(str1= =str4)的結(jié)果是什么呢?輸出結(jié)果是false,證明了String str4 = “hello “+var;
在內(nèi)存堆中會(huì)重新分配空間,而不是讓str4指向var的地址。換用一種定義方法:str4 = (“hello “+var4).intern();intern()方法告訴編譯器將此結(jié)果放到String pool里,因此,System.out.println(str1= =str4)輸出結(jié)構(gòu)將是true;
轉(zhuǎn)載于:https://www.cnblogs.com/guoziyi/p/5993085.html
總結(jié)
以上是生活随笔為你收集整理的java中String相等问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自动化软件部署的shell脚本
- 下一篇: 《java入门第一季》之类String类