成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

Java String常量池

leejan97 / 1001人閱讀

摘要:前者在中開(kāi)辟一個(gè)常量,并返回相應(yīng)的引用,而后者是在中開(kāi)辟一個(gè)常量,再返回相應(yīng)的對(duì)象。方法方法,可以在期間將常量加入到常量池。方法返回這個(gè)新創(chuàng)建的常量的引用。

1. String實(shí)例的初始化

String類(lèi)型的初始化在Java中分為兩類(lèi):

一類(lèi)是通過(guò)雙引號(hào)包裹一個(gè)字符來(lái)初始化;

另一類(lèi)是通過(guò)關(guān)鍵字new 像一個(gè)普通的對(duì)象那樣初始化一個(gè)String實(shí)例。

前者在constant pool中開(kāi)辟一個(gè)常量,并返回相應(yīng)的引用,而后者是在heap中開(kāi)辟一個(gè)常量,再返回相應(yīng)的對(duì)象。所以,兩者的reference肯定是不同的:

public static void main(String... args) {
    String s1 = "abcd";
    String s2 = new String("abcd");
    System.out.println(s1 == s2);   // false
}

而constant pool中的常量是可以被共享用于節(jié)省內(nèi)存開(kāi)銷(xiāo)和創(chuàng)建時(shí)間的開(kāi)銷(xiāo)(這也是引入constant pool的原因)。例如:

public static void main(String... args) {
    String s1 = "abcd";
    String s2 = "abcd";
    System.out.println(s1 == s2);   // true
}

結(jié)合這兩者,其實(shí)還可以回答另外一個(gè)常見(jiàn)的面試題目:

public static void main(String... args) {
    String s = new String("abcd");
}

這句話創(chuàng)建了幾個(gè)對(duì)象?

首先毫無(wú)疑問(wèn),"abcd"本身是一個(gè)對(duì)象,被放于常量池。而由于這里使用了new關(guān)鍵字,所以s得到的對(duì)象必然是被創(chuàng)建在heap里的。所以,這里其實(shí)一共創(chuàng)建了2個(gè)對(duì)象。

但tricky的部分是,如果在這個(gè)函數(shù)被調(diào)用前的別的地方,已經(jīng)有了"abcd"這個(gè)字符串,那么它就事先在constant pool中被創(chuàng)建了出來(lái)。此時(shí),這里就只會(huì)創(chuàng)建一個(gè)對(duì)象,即創(chuàng)建在heap的new String("abcd")對(duì)象。

但String的內(nèi)存分配,遠(yuǎn)遠(yuǎn)沒(méi)有這么簡(jiǎn)單。對(duì)于String的拼接,需要做更深入的理解和思考。

2. String的拼接

下面看一個(gè)問(wèn)題:

public static void main(String... args) {
    String s1 = "hell" + "o";
    String s2 = "h" + "ello";
    System.out.println(s1 == s2);   // true
    System.out.println(s1 == "hello");  // true
    System.out.println(s2 == "hello");  // true
    System.out.println("hello" == "hello"); // true
    
    // ------------------------
    
    String c1 = "ab";
    String c2 = c1 + "c";
    System.out.println(c2 == "abc");  // false
    
}

前面四個(gè)輸出其實(shí)很容易理解,最終的結(jié)果,都指向了constant pool里的一個(gè)常量"hello"。但奇怪的是,最后一個(gè)輸出也是"abc",并且還都是用指向constant pool中常量的變量來(lái)做的拼接,但卻得到了一個(gè)false的結(jié)果。

原因是,Java的String拼接有兩個(gè)規(guī)則:

對(duì)于拼接的值,如果都是雙引號(hào)包裹字符串的形式,則將結(jié)果放于constant pool,如果constant pool已經(jīng)有這個(gè)值了,則直接返回這個(gè)已有值。

而如果拼接的值中,有一個(gè)是非雙引號(hào)包裹字符串的形式,則從heap中開(kāi)辟一個(gè)新的區(qū)域保存常量。也即是使用了String變量來(lái)做拼接的情況。

在這樣的大原則下,對(duì)聲明為final的String變量需要做更多的考慮:

如果String變量被聲明為final時(shí)就已經(jīng)被賦值,則它被編譯器自動(dòng)處理為常量,因而它就會(huì)被當(dāng)作常量池的變量來(lái)處理。

public class ConstantPool {
    public static final String s1 = "ab";
    public static final String s2 = "cd";
    
    public static void main(String... args) {
        String s = s1 + s2;
        String ss = "abcd";
        
        System.out.println(s == ss);  // true
    }
}

而如果聲明為final的字符串沒(méi)有在聲明時(shí)被賦值,則編譯器無(wú)法事先決定它的準(zhǔn)確值,所以依舊會(huì)把它當(dāng)作一個(gè)變量來(lái)處理。

public class ConstantPool {
    public static final String s1;
    public static final String s2;
    
    static {
        s1 = "ab";
        s2 = "cd";
    }
    
    public static void main(String... args) {
        String s = s1 + s2;
        String ss = "abcd";
        
        System.out.println(s == ss);  // false
    }
}
3. intern()方法

String.intern()方法,可以在runtime期間將常量加入到常量池(constant pool)。它的運(yùn)作方式是:

如果constant pool中存在一個(gè)常量恰好等于這個(gè)字符串的值,則inter()方法返回這個(gè)存在于constant pool中的常量的引用。

如果constant pool不存在常量恰好等于這個(gè)字符串的值,則在constant pool中創(chuàng)建一個(gè)新的常量,并將這個(gè)字符串的值賦予這個(gè)新創(chuàng)建的在constant pool中的常量。intern()方法返回這個(gè)新創(chuàng)建的常量的引用。

示例:

public static void main(String... args) {
    String s1 = "abcd";
    String s2 = new String("abcd");

    /**
     * s2.intern() will first search String constant pool,
     * of which the value is the same as s2.
     */
    String s3 = s2.intern();
    // As s1 comes from constant pool, and s3 is also comes from constant pool, they"re same.
    System.out.println(s1 == s3);
    // As s2 comes from heap but s3 comes from constant pool, they"re different.
    System.out.println(s2 == s3); 
}

/**
 * Output:
 *     true
 *     false
 */

回顧到最開(kāi)始的第一部分,為什么要引入intern()這個(gè)函數(shù)呢?就是因?yàn)?,雖然"abcd"是被分配在constant pool里的,但是,一旦使用new String("abcd")就會(huì)在heap中新創(chuàng)建一個(gè)值為abcd的對(duì)象出來(lái)。試想,如果有100個(gè)這樣的語(yǔ)句,豈不是就要在heap里創(chuàng)建100個(gè)同樣值的對(duì)象?!這就造成了運(yùn)行的低效和空間的浪費(fèi)。

于是,如果引入了intern()它就會(huì)直接去constant pool找尋是否有值相同的String對(duì)象,這就極大地節(jié)省了空間也提高了運(yùn)行效率。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/77062.html

相關(guān)文章

  • java 為什么需要常量

    摘要:常量池探秘每個(gè)文件編譯為文件后,都將產(chǎn)生當(dāng)前類(lèi)獨(dú)有的常量池,我們稱(chēng)之為靜態(tài)常量池。文件中的常量池包含兩部分字面值和符號(hào)引用。方法的調(diào)用成員變量的訪問(wèn)最終都是通過(guò)運(yùn)行時(shí)常量池來(lái)查找具體地址的。其中,表示將一個(gè)常量加載到操作數(shù)棧。 java中講的常量池,通常指的是運(yùn)行時(shí)常量池,它是方法區(qū)的一部分,一個(gè)jvm實(shí)例只有一個(gè)運(yùn)行常量池,各線程間共享該運(yùn)行常量池。 java內(nèi)存模型中將內(nèi)存分為堆和...

    Yuanf 評(píng)論0 收藏0
  • 方法區(qū)到底是個(gè)什么鬼

    摘要:那方法區(qū)里都存著什么呢先拋結(jié)論靜態(tài)變量常量類(lèi)信息構(gòu)造方法接口定義運(yùn)行時(shí)常量池存在方法區(qū)中。動(dòng)態(tài)常量池運(yùn)行時(shí)常量池是方法區(qū)的一部分,是一塊內(nèi)存區(qū)域。文件常量池將在類(lèi)加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。 一、方法區(qū)與永久代 這兩個(gè)是非常容易混淆的概念,永久代的對(duì)象放在方法區(qū)中,就會(huì)想當(dāng)然地認(rèn)為,方法區(qū)就等同于持久代的內(nèi)存區(qū)域。事實(shí)上兩者是這樣的關(guān)系: 《Java虛擬機(jī)規(guī)范》只是規(guī)定了有方...

    binaryTree 評(píng)論0 收藏0
  • Java虛擬機(jī)中,字符串常量到底存放在哪

    摘要:的三種常量池此外,有三種常量池,即字符串常量池又叫全局字符串池文件常量池運(yùn)行時(shí)常量池。開(kāi)始虛擬機(jī)把字符串常量池位置從永久代挪到堆,又徹底取消,把諸如之類(lèi)的元數(shù)據(jù)都挪到堆之外管理。 前言 前陣子和朋友討論一個(gè)問(wèn)題: 字符串常量歸常量池管理,那比如 String str = abc; abc這個(gè)對(duì)象是放在內(nèi)存中的哪個(gè)位置,是字符串常量池中還是堆? 這句代碼的abc當(dāng)然在常量池中,只有n...

    lewinlee 評(píng)論0 收藏0
  • 我終于搞清楚了和String有關(guān)的那點(diǎn)事兒。

    摘要:為了減少在中創(chuàng)建的字符串的數(shù)量,字符串類(lèi)維護(hù)了一個(gè)字符串常量池。但是當(dāng)執(zhí)行了方法后,將指向字符串常量池中的那個(gè)字符串常量。由于和都是字符串常量池中的字面量的引用,所以。究其原因,是因?yàn)槌A砍匾4娴氖且汛_定的字面量值。 String,是Java中除了基本數(shù)據(jù)類(lèi)型以外,最為重要的一個(gè)類(lèi)型了。很多人會(huì)認(rèn)為他比較簡(jiǎn)單。但是和String有關(guān)的面試題有很多,下面我隨便找兩道面試題,看看你能不能...

    paulli3 評(píng)論0 收藏0
  • java:String

    摘要:類(lèi)是類(lèi)它內(nèi)部的方法也默認(rèn)被修飾不能重寫(xiě)字符串常量池當(dāng)這樣聲明一個(gè)字符串會(huì)檢測(cè)字符串常量池中是否存在這個(gè)值的字符串如果存在就直接賦值給否則創(chuàng)建一個(gè)新的再賦值給當(dāng)連續(xù)用同樣的方式聲明兩個(gè)字符串并作比較結(jié)果為這個(gè)操作符比較的是什么對(duì)于基本變量比較 String類(lèi)是final類(lèi),它內(nèi)部的方法也默認(rèn)被final修飾,不能重寫(xiě). 字符串常量池 當(dāng)這樣聲明一個(gè)字符串 String str = h...

    U2FsdGVkX1x 評(píng)論0 收藏0
  • String的內(nèi)存模型,為什么String被設(shè)計(jì)成不可變的

    摘要:證明返回常量池中已存在的對(duì)象,不等于新建的對(duì)象。為什么要設(shè)計(jì)成一下內(nèi)容來(lái)自發(fā)現(xiàn)百度的中文版本基本也是此文的翻譯版??傊踩院妥址A砍鼐彺媸潜辉O(shè)計(jì)成不可變的主要原因。 String是Java中最常用的類(lèi),是不可變的(Immutable), 那么String是如何實(shí)現(xiàn)Immutable呢,String為什么要設(shè)計(jì)成不可變呢? 前言 關(guān)于String,收集一波基礎(chǔ),來(lái)源標(biāo)明最后,不確...

    vspiders 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<