1.判定定義為String類型的st1和st2是否相等,為什么
package string;
public class Demo2_String {
public static void main(String[] args) {
String st1 = "abc";
String st2 = "abc";
System.out.println(st1 == st2);
System.out.println(st1.equals(st2));
}
}
輸出結(jié)果:
第一行:true
第二行:true
分析:
先看第一個(gè)打印語句落蝙,在Java中==這個(gè)符號(hào)是比較運(yùn)算符织狐,它可以基本數(shù)據(jù)類型和引用數(shù)據(jù)類型是否相等,如果是基本數(shù)據(jù)類型筏勒,==比較的是值是否相等移迫,如果是引用數(shù)據(jù)類型,==比較的是兩個(gè)對(duì)象的內(nèi)存地址是否相等管行。
字符串不屬于8中基本數(shù)據(jù)類型起意,字符串對(duì)象屬于引用數(shù)據(jù)類型,在上面把“abc”同時(shí)賦值給了st1和st2兩個(gè)字符串對(duì)象病瞳,指向的都是同一個(gè)地址揽咕,所以第一個(gè)打印語句中的==比較輸出結(jié)果是 true
然后我們看第二個(gè)打印語句中的equals的比較,我們知道套菜,equals是Object這個(gè)父類的方法亲善,在String類中重寫了這個(gè)equals方法。
在JDK API 1.6文檔中找到String類下的equals方法逗柴,點(diǎn)擊進(jìn)去可以看大這么一句話“將此字符串與指定的對(duì)象比較蛹头。當(dāng)且僅當(dāng)該參數(shù)不為null,并且是與此對(duì)象表示相同字符序列的String 對(duì)象時(shí)戏溺,結(jié)果才為 true渣蜗。” 注意這個(gè)相同字符序列旷祸,在后面介紹的比較兩個(gè)數(shù)組耕拷,列表,字典是否相等托享,都是這個(gè)邏輯去寫代碼實(shí)現(xiàn)骚烧。
由于st1和st2的值都是“abc”浸赫,兩者指向同一個(gè)對(duì)象,當(dāng)前字符序列相同赃绊,所以第二行打印結(jié)果也為true既峡。
下面我們來畫一個(gè)內(nèi)存圖來表示上面的代碼,看起來更加有說服力碧查。
內(nèi)存過程大致如下:
1)運(yùn)行先編譯运敢,然后當(dāng)前類Demo2_String.class文件加載進(jìn)入內(nèi)存的方法區(qū)
2)第二步,main方法壓入棧內(nèi)存
3)常量池創(chuàng)建一個(gè)“abc”對(duì)象忠售,產(chǎn)生一個(gè)內(nèi)存地址
4)然后把“abc”內(nèi)存地址賦值給main方法里的成員變量st1传惠,這個(gè)時(shí)候st1根據(jù)內(nèi)存地址,指向了常量池中的“abc”档痪。
5)前面一篇提到,常量池有這個(gè)特點(diǎn)邢滑,如果發(fā)現(xiàn)已經(jīng)存在腐螟,就不在創(chuàng)建重復(fù)的對(duì)象
6)運(yùn)行到代碼 Stringst2 =”abc”, 由于常量池存在“abc”,所以不會(huì)再創(chuàng)建困后,直接把“abc”內(nèi)存地址賦值給了st2
7)最后st1和st2都指向了內(nèi)存中同一個(gè)地址乐纸,所以兩者是完全相同的。
2. 下面這句話在內(nèi)存中創(chuàng)建了幾個(gè)對(duì)象
String st1 = new String(“abc”);
答案是:在內(nèi)存中創(chuàng)建兩個(gè)對(duì)象摇予,一個(gè)在堆內(nèi)存汽绢,一個(gè)在常量池,堆內(nèi)存對(duì)象是常量池對(duì)象的一個(gè)拷貝副本侧戴。 另外宁昭,關(guān)注微信公眾號(hào):Java技術(shù)棧,在后臺(tái)回復(fù):面試酗宋,可以獲取我整理的 N 篇最新 Java 面試題整理积仗,都是干貨。
分析:
我們下面直接來一個(gè)內(nèi)存圖蜕猫。
當(dāng)我們看到了new這個(gè)關(guān)鍵字寂曹,就要想到,new出來的對(duì)象都是存儲(chǔ)在堆內(nèi)存回右。然后我們來解釋堆中對(duì)象為什么是常量池的對(duì)象的拷貝副本隆圆。
“abc”屬于字符串,字符串屬于常量翔烁,所以應(yīng)該在常量池中創(chuàng)建渺氧,所以第一個(gè)創(chuàng)建的對(duì)象就是在常量池里的“abc”。
第二個(gè)對(duì)象在堆內(nèi)存為啥是一個(gè)拷貝的副本呢蹬屹,這個(gè)就需要在JDK API 1.6找到String(String original)這個(gè)構(gòu)造方法的注釋:初始化一個(gè)新創(chuàng)建的 String 對(duì)象阶女,使其表示一個(gè)與參數(shù)相同的字符序列颊糜;換句話說,新創(chuàng)建的字符串是該參數(shù)字符串的副本秃踩。
所以衬鱼,答案就出來了,兩個(gè)對(duì)象憔杨。
3鸟赫、判定以下定義為String類型的st1和st2是否相等
package string;
public class Demo2_String {
public static void main(String[] args) {
String st1 = new String("abc");
String st2 = "abc";
System.out.println(st1 == st2);
System.out.println(st1.equals(st2));
}
}
答案:false 和 true
由于有前面兩道提內(nèi)存分析的經(jīng)驗(yàn)和理論,所以消别,我能快速得出上面的答案抛蚤。
==比較的st1和st2對(duì)象的內(nèi)存地址,由于st1指向的是堆內(nèi)存的地址寻狂,st2看到“abc”已經(jīng)在常量池存在岁经,就不會(huì)再新建,所以st2指向了常量池的內(nèi)存地址蛇券,所以==判斷結(jié)果輸出false缀壤,兩者不相等。
第二個(gè)equals比較纠亚,比較是兩個(gè)字符串序列是否相等塘慕,由于就一個(gè)“abc”,所以完全相等蒂胞。
內(nèi)存圖如下
4. 判定以下定義為String類型的st1和st2是否相等
package string;
public class Demo2_String {
public static void main(String[] args) {
String st1 = "a" + "b" + "c";
String st2 = "abc";
System.out.println(st1 == st2);
System.out.println(st1.equals(st2));
}
}
答案是:true 和 true
分析:
“a”,”b”,”c”三個(gè)本來就是字符串常量图呢,進(jìn)行+符號(hào)拼接之后變成了“abc”,“abc”本身就是字符串常量(Java中有常量優(yōu)化機(jī)制)骗随,所以常量池立馬會(huì)創(chuàng)建一個(gè)“abc”的字符串常量對(duì)象蛤织,在進(jìn)行st2=”abc”,這個(gè)時(shí)候,常量池存在“abc”鸿染,所以不再創(chuàng)建瞳筏。所以,不管比較內(nèi)存地址還是比較字符串序列牡昆,都相等姚炕。
5、判斷以下st2和st3是否相等
package string;
public class Demo2_String {
public static void main(String[] args) {
String st1 = "ab";
String st2 = "abc";
String st3 = st1 + "c";
System.out.println(st2 == st3);
System.out.println(st2.equals(st3));
}
}
答案:false 和 true
分析:
上面的答案第一個(gè)是false丢烘,第二個(gè)是true柱宦,第二個(gè)是true我們很好理解,因?yàn)楸容^一個(gè)是“abc”播瞳,另外一個(gè)是拼接得到的“abc”掸刊,所以equals比較,這個(gè)是輸出true赢乓,我們很好理解忧侧。
那么第一個(gè)判斷為什么是false石窑,我們很疑惑。同樣蚓炬,下面我們用API的注釋說明和內(nèi)存圖來解釋這個(gè)為什么不相等松逊。
首先,打開JDK API 1.6中String的介紹肯夏,找到下面圖片這句話经宏。
關(guān)鍵點(diǎn)就在紅圈這句話,我們知道任何數(shù)據(jù)和字符串進(jìn)行加號(hào)(+)運(yùn)算驯击,最終得到是一個(gè)拼接的新的字符串烁兰。+ 號(hào)操作到底做了什么?
上面注釋說明了這個(gè)拼接的原理是由StringBuilder或者StringBuffer類和里面的append方法實(shí)現(xiàn)拼接徊都,然后調(diào)用 toString() 把拼接的對(duì)象轉(zhuǎn)換成字符串對(duì)象沪斟,最后把得到字符串對(duì)象的地址賦值給變量。
結(jié)合這個(gè)理解暇矫,我們下面畫一個(gè)內(nèi)存圖來分析主之。
大致內(nèi)存過程
1)常量池創(chuàng)建“ab”對(duì)象,并賦值給st1袱耽,所以st1指向了“ab”
2)常量池創(chuàng)建“abc”對(duì)象杀餐,并賦值給st2干发,所以st2指向了“abc”
3)由于這里走的+的拼接方法朱巨,所以第三步是使用StringBuffer類的append方法,得到了“abc”枉长,這個(gè)時(shí)候內(nèi)存0x0011表示的是一個(gè)StringBuffer對(duì)象冀续,注意不是String對(duì)象。
4)調(diào)用了Object的toString方法把StringBuffer對(duì)象裝換成了String對(duì)象必峰。
5)把String對(duì)象(0x0022)賦值給st3
所以洪唐,st3和st2進(jìn)行==判斷結(jié)果是不相等,因?yàn)閮蓚€(gè)對(duì)象內(nèi)存地址不同吼蚁。
總結(jié):
這篇的面試題凭需,完全就是要求掌握J(rèn)DK API中一些注解和原理,以及內(nèi)存圖分析肝匆,才能得到正確的結(jié)果粒蜈,我承認(rèn)是畫內(nèi)存圖讓我理解了答案為什么是這樣。
畫完內(nèi)存圖之后旗国,得到答案枯怖,你確實(shí)會(huì)發(fā)現(xiàn)很有趣,最后才會(huì)有原來如此的感嘆能曾。
作者:Anthony_tester
原文:
https://blog.csdn.net/u011541946/article/details/79865160
本文僅供學(xué)習(xí)之用度硝,版權(quán)歸原作者所有肿轨,如有侵權(quán)請(qǐng)聯(lián)系刪除。
我將面試題和答案都整理成了PDF文檔蕊程,還有一套學(xué)習(xí)資料椒袍,涵蓋Java虛擬機(jī)、spring框架存捺、Java線程槐沼、數(shù)據(jù)結(jié)構(gòu)、設(shè)計(jì)模式等等捌治,但不僅限于此岗钩。
關(guān)注公眾號(hào)【java圈子】獲取資料,還有優(yōu)質(zhì)文章每日送達(dá)肖油。