成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

聊一聊讓我蒙蔽一晚上的各種常量池

Tamic / 2813人閱讀

摘要:注意運行時常量池存在于方法區(qū)中。一個在堆中,一個在字符串常量池中。注意,是把這個對象添加到字符串常量池。內(nèi)存中有一個基本類型封裝類的常量池。需要注意的是,和這兩個類并沒有對應(yīng)的常量池。

在寫之前我們先來看幾個問題,假如你對這些問題已經(jīng)很懂了的話,那大可不用看這篇文章,如果不大懂的話,那么可以看看我的想法。

問題1:

public static void main(String[] args){
    String t1 = new String("2");
    t1.intern();
    String t2 = "2";
    System.out.println(t1 == t2);
    
    String t3 = new String("2") + new String("2");
    t3.intern();
    String t4 = "22";
    System.out.println(t3 == t4);
}

答案輸出:

JDK1.6是 false false

JDK1.7是 false true;

問題2(把問題1的語句調(diào)換一下位置)

public static void main(String[] args){
    String t1 = new String("2");
    String t2 = "2";
    t1.intern();
    System.out.println(t1 == t2);
    
    String t3 = new String("2") + new String("2");
    String t4 = "22";
    t3.intern();
    System.out.println(t3 == t4);
}

答案輸出:
false false

對于這兩個問題,看了幾個人的博客,可謂百花齊放,越看越懵逼

問題3

public static void main(String[] args){
    Integer a = 1;
    Integer b = 2;
    Integer c = 3;
    Integer d = 3;
    Integer e = 321;
    Integer f = 321;
    Long g = 3L;
    
    System.out.println(c == d);
    System.out.Println(e == f);
    System.out.println(c == (a + b));
    System.out.println(c.equals(a+b));
    System.out.println(g == (a + b));
    System.out.println(g.equals(a + b));
}

答案輸出:

true

false

true

true

true

false

問題4:

運行時常量池與字符串常量池是什么關(guān)系?包含?

在解決問題之前,我們先來簡單了解一些常量池的一些知識點(大部分來源于周志明的深入Java虛擬機這本書)。

JVM中的幾種常量池 1.class文件常量池

在Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用于存放編譯期生成的各種字面量和符號引用。

這里簡單解釋下字面量和符號引用

字面量

字面量類似與我們平常說的常量,主要包括:

文本字符串:就是我們在代碼中能夠看到的字符串,例如String a = "aa"。其中"aa"就是字面量。

被final修飾的變量。

符號引用

主要包括以下常量:

類和接口和全限定名:例如對于String這個類,它的全限定名就是java/lang/String。

字段的名稱和描述符:所謂字段就是類或者接口中聲明的變量,包括類級別變量(static)和實例級的變量。

方法的名稱和描述符。所謂描述符就相當于方法的參數(shù)類型+返回值類型。

2.運行時常量池

我們上面說的class文件中的常量池,它會在類加載后進入方法區(qū)中的運行時常量池。并且需要的注意的是,運行時常量池是全局共享的,多個類共用一個運行時常量池。并且class文件中常量池多個相同的字符串在運行時常量池只會存在一份。

注意運行時常量池存在于方法區(qū)中。

3.字符串常量池

看名字我們就可以知道字符串常量池會用來存放字符串,也就是說常量池中的文本字符串會在類加載時進入字符串常量池。

那字符串常量池和運行時常量池是什么關(guān)系呢?上面我們說常量池中的字面量會在類加載后進入運行時常量池,其中字面量中有包括文本字符串,顯然從這段文字我們可以知道字符串常量池存在于運行時常量池中。也就存在于方法區(qū)中。

不過在周志明那本深入java虛擬機中有說到,到了JDK1.7時,字符串常量池就被移出了方法區(qū),轉(zhuǎn)移到了里了。

那么我們可以推斷,到了JDK1.7以及之后的版本中,運行時常量池并沒有包含字符串常量池,運行時常量池存在于方法區(qū)中,而字符串常量池存在于中。

說了這么多,現(xiàn)在我們開始來解決上面提出了問題。

解決問題

問題1:

public static void main(String[] args){
    String t1 = new String("1");
    t1.intern();
    String t2 = "1";
    System.out.println(t1 == t2);
    
    String t3 = new String("2") + new String("2");
    t3.intern();
    String t4 = "22";
    System.out.println(t3 == t4);
}

答案輸出:

JDK1.6是 false false。

JDK1.7是 false true;

在解決這個問題之前,我們先來看另外一道面試中經(jīng)常會問到的問題。

String t = new String("tt");

假如程序中只有這樣一行代碼,那么這行代碼創(chuàng)建了幾個對象?

我們上面說過,"tt"屬于字面量,那么它會在類加載之后存在于字符串常量池中,也就是說,在 String t = new String("tt")這句代碼執(zhí)行之前,字符串常量池就已經(jīng)創(chuàng)建了"tt"這個字符串對象了,我們都知道,new這個關(guān)鍵字會在堆中創(chuàng)建一個對象。

所以,這段代碼創(chuàng)建了兩個對象。一個在堆中,一個在字符串常量池中。

那么下面這段代碼又是創(chuàng)建了幾個對象呢?

String t1 = new String("tt");
String t2 = new String("tt");

答是這段代碼創(chuàng)建了三個對象,我們上面說了,字符串常量池只會保存一份內(nèi)容相同的字符串。也就是說,在這兩句代碼執(zhí)行之前,字符串常量池就已經(jīng)創(chuàng)建了內(nèi)容為"tt"的對象了。這兩句代碼執(zhí)行之后,又在堆中創(chuàng)建了兩個,所以一共創(chuàng)建了三個。

那么下面這段代碼又是創(chuàng)建了幾個對象?

String t = "tt";

答是1個,在這段代碼執(zhí)行之前,字符串常量池已經(jīng)創(chuàng)建了一個"tt"的對象,但由于這行代碼并非用new的方法,所以虛擬機會在字符串常量池中尋找是否有內(nèi)容為"tt"的字符串對象,如果有,則直接返回這個字符串的引用,所以最終結(jié)果只創(chuàng)建了一個對象。

回到我們的問題,在這里我們先解釋下String 的intern方法。

例如我們調(diào)用了t.intern()。

在JDK1.6的時候,調(diào)用了這個方法之后,虛擬機會在字符串常量池在查找是否有內(nèi)容與"tt"相等的對象,如果有,則返回這個對象,如果沒有,則會在字符串常量池中添加這個對象。注意,是把這個對象添加到字符串常量池。

到了JDK1.7之后,如果調(diào)用了intern這個方法,虛擬機會在字符串常量池在查找是否有內(nèi)容與"tt"相等的對象,如果有,則返回這個對象,如果沒有。則會在堆中把這個對象的引用復(fù)制添加到字符串常量池中。注意,這個時候添加的是對象在堆中的引用。

現(xiàn)在開始來分析問題中的代碼

t1 = new String("1")。

這句代碼執(zhí)行之前,字符串常量池中已經(jīng)有"t"這個對象,執(zhí)行之后會在堆中也創(chuàng)建一個"t"的對象,此時t1指向的是堆中的對象。

t1.intern();

這句代碼執(zhí)行之后,會在字符串常量池尋早內(nèi)容為"t"的對象,字符串常量池已經(jīng)存在這個對象了,把這個對象返回(不過返回之后并沒有變量來接收)。

t2 = "1"。

這句執(zhí)行后會在字符串常量池查找內(nèi)容為"t"的對象,字符串常量池已經(jīng)有這個對象了,返回給t2,此時t2指向的是常量池中的對象。

一個是常量池中的對象,一個是在堆中的對象,兩者能相等嗎?因此

t1 與 t2不相等。

接著下面

t3 = new String("2") + new String("2");

這段代碼調(diào)用之前,字符串常量池有一個"2"的對象,執(zhí)行之后,實際上會調(diào)用StringBuilder的append()方法類進行拼接,最后在堆中創(chuàng)建一個"22"的對象,注意,此時字面量并沒有"22"這個字符串,也就是說在字符串常量池并沒有"22"這個對象。此時t3指向堆中"22"這個對象

t3.intern();

執(zhí)行這個方法之后

在JDK1.6的時候,它在字符串常量池中并沒有找到內(nèi)容為"22"的對象,所以這個時候會把這個對象添加到字符串常量池,并把這個對象返回(此時并沒有變量來接收這個返回的對象)。注意添加的是對象,而并非引用。

t4 = "22"。

這句代碼執(zhí)行后,會返回字符串常量池中內(nèi)容為"22"對象,此時t4指向的是字符串常量池中的對象

顯然,一個對象在字符串常量池,一個在堆中,兩個對象并非是同一個對象,因此在JDK1.6的時候,t3與t4不相等。

但是在JDK1.7的時候

t3.intern()執(zhí)行之后,由于在字符串常量池在并沒有內(nèi)容為"22"的對象,所以會把堆中該對象的引用賦值到字符串常量池。注意此時字符串常量池保存的是堆中這個對象的引用。

t4 = "22"。

執(zhí)行這句代碼之后,從字符串常量池返回給t4的是堆中對象的引用。此時t4指向的實際上是堆中對象的引用,也就是說,t3和t4指向的是同一個對象。

因此t3與t4相等。

不知道你明白了沒有?反正我是搞了好久才明白...

問題2

至于問題2,我就只講下半部分的代碼,上半部分如果你看懂了問題1,那么問題2也差不多自然懂了。

String t3 = new String("2") + new String("2");
String t4 = "22";
t3.intern();
System.out.println(t3 == t4);

t3 = new String("2") + new String("2")。

這段代碼調(diào)用之前,字符串常量池有一個"2"的對象,執(zhí)行之后,實際上會調(diào)用StringBuilder的append()方法類進行拼接,最后在堆中創(chuàng)建一個"22"的對象。此時t3指向堆中"22"這個對象

t4 = "22"。

這句代碼執(zhí)行之前,字符串常量池已經(jīng)存在"22"這個對象了,所有直接把這個對象返回給t4,此時t4指向的是字符串常量池中的對象.

所以t3和t4肯定不是同一個對象啊,t3.intern這句幾乎可以忽略,不會給t3和t4造成任何影響。

問題3
public static void main(String[] args){
    Integer a = 1;
    Integer b = 2;
    Integer c = 3;
    Integer d = 3;
    Integer e = 321;
    Integer f = 321;
    Long g = 3L;
    
    System.out.println(c == d);
    System.out.Println(e == f);
    System.out.println(c == (a + b));
    System.out.println(c.equals(a+b));
    System.out.println(g == (a + b));
    System.out.println(g.equals(a + b));
}

對于這個問題,我簡單說一下可能你就懂了。

(1). 內(nèi)存中有一個java基本類型封裝類的常量池。這些類包括
Byte, Short, Integer, Long, Character, Boolean。需要注意的是,F(xiàn)loat和Double這兩個類并沒有對應(yīng)的常量池。

(2).上面5種整型的包裝類也只是在對象數(shù)值在-128~127才可以使用這些常量池。

(3). 在周志明的那本虛擬機中有這樣一句話:包裝類的
"=="運行符在不遇到算術(shù)運算的情況下不會自動拆箱,以及他們的equals()方法不處理數(shù)據(jù)類型的關(guān)系,可以推斷出如果遇到“==”兩邊有算術(shù)運算是話就會自動拆箱和進行數(shù)據(jù)類型轉(zhuǎn)換處理。

(4).Long的equals方法會先判斷是否是Long類型。

(5).無論是Integer還是Long,他們的equals方法比較的是數(shù)值。

所以:

System.out.println(c == d)。

由于常量池的作用,c與d指向的是同一個對象(注意此時的==比較的是對象,也就是地址,而不是數(shù)值)。因此為true

System.out.println(e == f)。

由于321超過了127,因此常量池失去了作用,所以e和f數(shù)值雖然相同,但不是同一個對象,以此為false。

System.out.println(c == (a+b))。

此時==兩邊有算術(shù)運算,會進行拆箱,因此此時比較的是數(shù)值,而并非對象。因此為true。

System.out.println(c.equals(a+b))

c與a+b的數(shù)值相等,為true。

System.out.pirnln(g == (a + b))

由于==兩邊有算術(shù)運算,所以比較的是數(shù)值,因此為true。

System.out.println(g.equals(a+b))。

Long類型的equal在比較是時候,會先判斷a+b是否為Long類型,顯然a+b不是,因此false

問題到此就結(jié)束了,以上便是自己的理解,以上如果有不對勁的地方,非常歡迎你的指點。

。

關(guān)注公眾號「苦逼的碼農(nóng)」,獲取更多原創(chuàng)文章,后臺回復(fù)「禮包」送你一份特別的大禮包

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76879.html

相關(guān)文章

  • 物聯(lián)網(wǎng)嵌入式芯片內(nèi)容結(jié)構(gòu)

    摘要:摘要物聯(lián)網(wǎng)嵌入式芯片,存儲是數(shù)據(jù)核心之一,這個對于編程和設(shè)計的人來說又比較陌生,今天來說說中的內(nèi)存結(jié)構(gòu)。棧堆棧又稱為?;蚨询B,是計算機科學(xué)中的一種抽象資料類型,只允許在有序的線性資料集合的一端稱為堆棧頂端,進行加入數(shù)據(jù)和移除數(shù)據(jù)的運算。 摘要:物聯(lián)網(wǎng)嵌入式芯片,存儲是數(shù)據(jù)核心之一,這個對于...

    whlong 評論0 收藏0
  • 程序語言

    摘要:一面應(yīng)該還問了其他內(nèi)容,但是兩次面試多線程面試問題和答案采訪中,我們通常會遇到兩個主題采集問題和多線程面試問題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問:Ja...

    mtunique 評論0 收藏0
  • 程序語言

    摘要:一面應(yīng)該還問了其他內(nèi)容,但是兩次面試多線程面試問題和答案采訪中,我們通常會遇到兩個主題采集問題和多線程面試問題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問:Ja...

    stefan 評論0 收藏0
  • [系列]WEB前端安全那些事兒

    摘要:所以今天,就和大家一起聊一聊前端的安全那些事兒。我們就聊一聊前端工程師們需要注意的那些安全知識。殊不知,這不僅僅是違反了的標準而已,也同樣會被黑客所利用。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/blog... 隨著互聯(lián)網(wǎng)的發(fā)達,各種WEB應(yīng)用也變得越來越復(fù)雜,滿足了用戶的各種需求...

    AZmake 評論0 收藏0
  • [系列]前端功能統(tǒng)計那些事兒

    摘要:歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面不僅僅是代碼什么是功能統(tǒng)計作為一名開發(fā),我們的產(chǎn)品發(fā)布出去之后,無論是產(chǎn)品還是運營,其實都是想及時了解產(chǎn)品對用戶產(chǎn)生的影響的。下一章,我們將繼續(xù)聊聊速度統(tǒng)計。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://segmentfault.com/bl...

    PAMPANG 評論0 收藏0

發(fā)表評論

0條評論

Tamic

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<