国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一篇文章帶你徹底弄懂Java的==符號(hào)

這篇具有很好參考價(jià)值的文章主要介紹了一篇文章帶你徹底弄懂Java的==符號(hào)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

本篇文章6735字,大概閱讀時(shí)間20分鐘。本文中使用到的JDK版本為1.8.0_301

目錄

==符號(hào)的定義

基本類型中==符號(hào)的判斷

String類型中==符號(hào)的判斷


==符號(hào)的定義

? ? ? ? 在Java中==符號(hào)的作用分為兩類:

? ? ? ? 1:==符號(hào)在八種基本類型的作用是比較對(duì)應(yīng)基本類型的數(shù)值是否相等

? ? ? ? 2:==符號(hào)在對(duì)象類型的作用是比較兩個(gè)對(duì)象是否相等

? ? ? ? 在對(duì)象類型中又有兩類特殊情況,一種是基本類型中包裝類對(duì)象,一種是String對(duì)象。前者由于存在緩存導(dǎo)致,后綴則是有字符串常量池的存在導(dǎo)致。

基本類型中==符號(hào)的判斷

????????在基本類型中==符號(hào)的作用是判斷基本類型的數(shù)值是否相同

        int i1 = 1;
        int i2 = 2;
        int i3 = 1;
        System.out.println(i1 == i2); //false
        System.out.println(i1 == i3); //true

        char c1 = 'a';
        char c2 = 'b';
        char c3 = 'a';

        System.out.println(c1 == c2); //false
        System.out.println(c1 == c3); //true

? ? ? ? 在基本類型的包裝類中由于存在緩存以及自動(dòng)拆箱/裝箱,導(dǎo)致==符號(hào)的使用存在一定的差異,下面將會(huì)解釋到。

? ? ? ? 首先基本類型和包裝類對(duì)應(yīng)關(guān)系

基本類型 包裝類型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

? ? ? ? 在看一段代碼(建議將代碼復(fù)制粘貼到別處,下文會(huì)經(jīng)常提到這段代碼中的內(nèi)容)

        Integer i1 = 127; //數(shù)值127 自動(dòng)裝箱
        Integer i2 = 127; //數(shù)值127 自動(dòng)裝箱
        System.out.println(i1 == i2);  //true

        Integer i3 = 128; //數(shù)值128 自動(dòng)裝箱
        Integer i4 = 128; //數(shù)值128 自動(dòng)裝箱
        System.out.println(i3 == i4);  //false

        Integer i5 = new Integer(127);
        Integer i6 = new Integer(127);
        System.out.println(i5 == i6);  //false

        Integer i7 = new Integer(128);
        Integer i8 = new Integer(128);
        System.out.println(i7 == i8);  //false

        int i9 = 127;
        System.out.println(i1 == i9); // true i1自動(dòng)拆箱
        System.out.println(i5 == i9); // true i9自動(dòng)拆箱

? ? ? ? 首先i1==i2(true)和i3==i4(false)?這兩種情況,要解釋這兩種情況,先看看自動(dòng)拆箱/裝箱背后的邏輯。將上面這段代碼編譯成Class文件,然后通過javap命令進(jìn)行反編譯,查看字節(jié)碼的執(zhí)行邏輯?。

????????javap是jdk自帶的反解析工具。它的作用就是根據(jù)class字節(jié)碼文件,反解析出當(dāng)前類對(duì)應(yīng)的code區(qū) (字節(jié)碼指令)、局部變量表、異常表和代碼行偏移量映射表、常量池等信息。

????????? 通過執(zhí)行 javap -c /xx.class?命令,輸出下面內(nèi)容java中==,java,java,jvm,開發(fā)語言

????????在輸出內(nèi)容中,可以看到反匯編后,代碼Integer i1 = 127在=號(hào)右邊的127會(huì)調(diào)用Integer.valueOf(127)方法,將數(shù)值127包裝成Integer(127)的Integer對(duì)象,同理i2、i3、i4也是相同原理。通過上述內(nèi)容可以看出,自動(dòng)裝箱就是調(diào)用包裝類的valueOf()方法將基本類型的值封裝成對(duì)應(yīng)的包裝類對(duì)象。

? ? ? ? 現(xiàn)在我們?nèi)タ匆幌翴nteger.valueOf方法具體做了哪些事情

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
}

? ? ? ? 在看一下IntegerCache的代碼

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h; //127
            //創(chuàng)建一個(gè)Integer類型的cache數(shù)組長度為256
            cache = new Integer[(high - low) + 1];
            int j = low;
            //從下標(biāo)0開始依次存入-128 -127 .... 126 127
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

? ? ? ? 在valueOf()方法中首先會(huì)判斷傳入的i在不在-128~127之間,如果在這區(qū)間就會(huì)調(diào)用 IntegerCache.cache,而cache是一個(gè)Integer對(duì)象的數(shù)組,并且是在static代碼塊中進(jìn)行初始化,在IntegerCache對(duì)象初始化完成后,cache數(shù)組已經(jīng)初始化完畢。所以如果在-128~127之間,直接返回cache中已經(jīng)創(chuàng)建好的Integer對(duì)象,如果不在-128~127之間則會(huì)重新new一個(gè)Integer對(duì)象。

? ? ? ? 通過上面的分析就可以得出 i1=127和i2=127在進(jìn)行自動(dòng)裝箱的時(shí)候,通過valueOf方法返回的都是同一個(gè)已經(jīng)在cache中存在的Integer(127)對(duì)象,而i3=128和i4=128則是直接通過new的方式創(chuàng)建的兩個(gè)不同的Integer對(duì)象。而==符號(hào)在比較兩個(gè)對(duì)象的時(shí)候是判斷兩個(gè)對(duì)象是否相等,明顯i1和i2都是cache緩存中的同一個(gè)對(duì)象所以==比較結(jié)果為true,而i3和i4是兩個(gè)不同的對(duì)象,所以==比較的結(jié)果是false。

? ? ? ? 注意:通過上面的分析,在包裝類比較數(shù)值是否相等的時(shí)候需要使用equals方法進(jìn)行,不要使用==進(jìn)行比較數(shù)值是否相等,由于有緩存的存在可能導(dǎo)致結(jié)果出現(xiàn)差異。

? ? ? ? 繼續(xù)看上面的代碼,在?i5、i6、i7、i8都是創(chuàng)建的不同的Integer對(duì)象,所以使用==符號(hào)的時(shí)候比較的結(jié)果都是false。

? ? ? ? 在i9處定義了一個(gè)數(shù)值為127的常量,i1==i9和i5==i9比較的時(shí)候,我們繼續(xù)查看反編譯? ? ?java中==,java,java,jvm,開發(fā)語言?????????在i1==i9和i5==i9比較的時(shí)候 i1和i5會(huì)調(diào)用intValue()方法,獲取Integer對(duì)象中存儲(chǔ)的常量值

public int intValue() {return value;}

????????所以i1==i9和i5==i9比較的是數(shù)值大小,在基本類型和包裝類型進(jìn)行比較的時(shí)候,包裝類型通過調(diào)用xxxValue()方法獲取對(duì)應(yīng)的常量值,這個(gè)就是自動(dòng)拆箱。?

????????總結(jié):

? ? ? ? 1:在引用類型是包裝類型的時(shí)候,而等號(hào)右邊是基本類型的字面量,類似Integer i = 127的時(shí)候,會(huì)觸發(fā)自動(dòng)裝箱,調(diào)用對(duì)應(yīng)的valueOf()方法將字面量封裝成包裝類型。

? ? ? ? 2:在基本類型的字面量和包裝類對(duì)象比較的時(shí)候,包裝類對(duì)象會(huì)調(diào)用對(duì)應(yīng)xxxValue()方法,獲取對(duì)象中的字面量值,所以比較的是字面量的值。

? ? ? ? 3:基本類型的自動(dòng)裝箱就是調(diào)用對(duì)應(yīng)包裝類的valueOf()方法,而自動(dòng)拆箱就是包裝類調(diào)用xxxValue()方法。

? ? ? ? 上面介紹的時(shí)候是使用int和int的包裝類Integer作為例子,下面將會(huì)羅列出八種基本類型全部情況。?

基本類型 包裝類型 緩存(valueOf方法)
byte Byte 存在緩存 -128~127之間
short Short 存在緩存 -128~127之間
int Integer 存在緩存 -128~127之間
long Long 存在緩存 -128~127之間
float Float 沒有緩存
double Double 沒有緩存
char Character 存在緩存 0~127之間
boolean Boolean 存在緩存 true/false

String類型中==符號(hào)的判斷

? ? ? ? 本文所用的JDK版本為1.8.0_301,在不同JDK版本中字符串常量池存在差異,所以接下來代碼的運(yùn)行環(huán)境都是1.8.0_301版本。

? ? ? ? 在JDK8中字符串常量池的定義為:字符串常量池在堆中存儲(chǔ)

? ? ? ? 先看下面代碼

String s1 = "abc";
String s2 = new String("abc");

? ? ? ? 通過javap命令進(jìn)行反編譯

java中==,java,java,jvm,開發(fā)語言

? ? ? ? 上圖中l(wèi)dc、astore這些JVM指令的解釋可以查看這里,使用頁面搜索來查找

? ? ? ? 解讀反編譯后的內(nèi)容

? ? ? ? Code 0:ldc指令將"abc"字面量存儲(chǔ)到字符串常量池中,也就是String s1 = "abc"。如果常量池中不存在則需要在常量池中創(chuàng)建,如果常量池中有則直接使用。

? ? ? ? Code 2:將s1引用保存到局部變量表中

? ? ? ? Code 3:new一個(gè)字符串對(duì)象,對(duì)應(yīng)的是String s2 = new String("abc")

? ? ? ? Code 6:將創(chuàng)建的對(duì)象s2壓入操作數(shù)棧中

? ? ? ? Code 7:由于s2中的字符串"abc"已經(jīng)存在在字符串常量池中,所以不需要再次創(chuàng)建"abc",直接從常量池中獲取

? ? ? ? Code 9:初始化s2對(duì)象,調(diào)用String(str String)的構(gòu)造方法,將已經(jīng)存在常量池中的"abc"字符串傳入構(gòu)造方法,完成s2對(duì)象的創(chuàng)建

? ? ? ? Code 12:將s2引用保存到局部變量表中

java中==,java,java,jvm,開發(fā)語言

?????????再將上面一段代碼,順序顛倒

 String s2 = new String("abc");
 String s1 = "abc";

? ? ? ? 再通過javap命令進(jìn)行反編譯

java中==,java,java,jvm,開發(fā)語言

????????解讀反編譯后的內(nèi)容

? ? ? ? Code 0:new一個(gè)字符串對(duì)象,對(duì)應(yīng)的是String s2 = new String("abc")

? ? ? ? Code 3:將創(chuàng)建的對(duì)象s2壓入操作數(shù)棧中

? ? ? ? Code 4:ldc指令將new String("abc")中的"abc"字面量存儲(chǔ)到字符串常量池中,如果常量池中不存在則需要在常量池中創(chuàng)建,如果常量池中有則直接使用。這里"abc"由于在常量池中不存在,則第一次創(chuàng)建。

? ? ? ? Code 6:初始化s2對(duì)象,調(diào)用String(str String)的構(gòu)造方法,將已經(jīng)存在常量池中的"abc"字符串傳入構(gòu)造方法,完成s2對(duì)象的創(chuàng)建

? ? ? ? Code 9:將s2引用保存到局部變量表中

? ? ? ? Code 10:創(chuàng)建String s1 = "abc",由于"abc"已經(jīng)在常量池中存在,則無需再次創(chuàng)建,直接使用常量池中的"abc"。

? ? ? ? Code 12:將創(chuàng)建的對(duì)象s1壓入操作數(shù)棧中?

java中==,java,java,jvm,開發(fā)語言

?? ? ? ? 通過上面的分析,總結(jié)如下:

? ? ? ? 1:jdk8中字符串常量池存是在堆中創(chuàng)建一塊區(qū)域進(jìn)行存儲(chǔ)。

? ? ? ? 2:字符串字面值的創(chuàng)建是直接在字符串常量池中進(jìn)行創(chuàng)建,在創(chuàng)建前會(huì)檢查常量池中是否已經(jīng)存在對(duì)應(yīng)的字符串,如果不存在則在常量池中進(jìn)行創(chuàng)建,存在則直接使用。

? ? ? ? 3:如果通過new 來創(chuàng)建字符串對(duì)象,首先會(huì)判斷字面值是否在常量池中已經(jīng)存在,如果不存在則在常量池中進(jìn)行創(chuàng)建,存在則直接使用。然后將常量池中的字符串引用傳遞給在堆中創(chuàng)建的字符串對(duì)象,再將堆中創(chuàng)建的字符串對(duì)象傳遞給s2。

? ? ? ? 通過上面的分析還可得出一個(gè)常見的面試問題String s2 = new String("abc"),s2的創(chuàng)建過程一共創(chuàng)建了幾次對(duì)象?

? ? ? ? 答案是一次或者兩次

? ? ? ? 一次:類似第一種情況,常量池中已經(jīng)存在了對(duì)應(yīng)的"abc"字符串,所以只需要在堆中創(chuàng)建new String("abc")對(duì)象即可,然后將堆中的對(duì)象指向s2。

? ? ? ? 兩次:類似第二種情況,常量池中不存在,則首先要在常量池中創(chuàng)建一次"abc"字符串對(duì)象,然后再在堆中第二次創(chuàng)建new String("abc")對(duì)象,并且把常量池中的對(duì)象指向堆中的對(duì)象,然后堆中的對(duì)象再指向s2。

? ? ? ? 通過上面的分析,接下來可以研究==符號(hào)在字符串中的判斷

        String s1 = "abc";
        String s2 = "abc";
        String s3 = new String("abc");
        String s4 = new String("abc");
        System.out.println(s1 == s2); //true
        System.out.println(s1 == s3); //false
        System.out.println(s3 == s4); //false

? ? ? ? s1和s2都是在常量池中創(chuàng)建的,并且在s2創(chuàng)建的時(shí)候"abc"字符串已經(jīng)存在,所以s2得引用指向的是s1,故s1==s2為true,而s3和s4都是在堆上創(chuàng)建的對(duì)象,雖然s3和s4中字符串指向的是常量池中的同一個(gè)"abc",但是s3和s4是堆上的不同對(duì)象所以 s1==s3和s3==s4為false

java中==,java,java,jvm,開發(fā)語言????????下面在分析幾種使用+拼接字符串的情況下==符號(hào)的判斷

? ? ? ? 在判斷之前先熟悉兩個(gè)概念

? ? ? ??常量折疊優(yōu)化:是指Java在編譯期做的一個(gè)優(yōu)化,將一些表達(dá)式在編譯期能計(jì)算好的,不用放到運(yùn)行期間進(jìn)行計(jì)算

? ? ? ? 例如? 1+1或者 "ab" +"c"這些可以在編譯期直接計(jì)算出表達(dá)式的結(jié)果 2和"abc"。

? ? ? ? 字面量:指直接寫在代碼中的數(shù)字、字符串或布爾值。例如數(shù)值123 123.11或者字符串"abc"直接在代碼中定義的值。

? ? ? ? 接下來看+號(hào)拼接字符串的情況下==符號(hào)的判斷

? ? ? ? 第一種情況:常量折疊優(yōu)化

        String s1 = "abc";
        String s2 = "a" + "b" + "c";
        System.out.println(s1 == s2); //true

? ? ? ? 在這種情況下 s2在編譯期間會(huì)進(jìn)行常量折疊優(yōu)化,直接拼接成"abc"。

java中==,java,java,jvm,開發(fā)語言? ? ? ? 第二種情況:拼接字符串中有一個(gè)是變量或是通過new關(guān)鍵字實(shí)例化的對(duì)象

        String s1 = "abc";
        String s2 = "ab";
        String s3 = s2 + "c";
        String s4 = new String("ab") + "c";
        String s5 = new String("ab") + new String("c");
        System.out.println(s1 == s3); //false
        System.out.println(s1 == s4); //false
        System.out.println(s1 == s5); //false

? ? ? ? 這種情況下,由于無法再編譯器確定對(duì)象的值,只能在運(yùn)行期間確定,s3、s4、s5都是在堆上創(chuàng)建的不同的字符串對(duì)象,所以比較結(jié)果都是false。? ??java中==,java,java,jvm,開發(fā)語言

? ? ? ? ?第三種情況:final修飾的字面量實(shí)例化的字符串編譯器在編譯前也可以直接確認(rèn)它的值。

        String s1 = "abc";
        final String s2 = "ab";
        String s3 = s2 + "c";
        String s4 = s2 + new String("c");
        System.out.println(s1 == s3);  //true
        System.out.println(s1 == s4);  //false

? ? ? ? s2是被final修飾的常量,其值不會(huì)發(fā)生改變。在s3=s2+"c",可以看成 s3="ab"+"c"。所以在上面的判斷中s1==s3為true。?而s4中雖然s2是常量帶時(shí)候+后面跟著一個(gè)變量,所以在堆中創(chuàng)建了s4,故s1==s4為false。java中==,java,java,jvm,開發(fā)語言

? ? ? ? 通過上面的分析,我們可以得出如下結(jié)論:

? ? ? ? 1:字符串的字面量都是存在在常量池中,并且如果字面量在常量池中已經(jīng)存在,則不會(huì)再次創(chuàng)建。

? ? ? ? 2: 由于有常量折疊優(yōu)化的存在,字符串的字面量在使用+號(hào)拼接的時(shí)候可以在編譯期確定其值

? ? ? ? 3:+號(hào)拼接字符串中有一個(gè)是變量或是通過new關(guān)鍵字實(shí)例化的對(duì)象,都是會(huì)在堆中創(chuàng)建其對(duì)象

? ? ? ? 4:final修飾的字面量實(shí)例化的字符串編譯器在編譯前也可以直接確認(rèn)它的值。

? ? ? ? 還有在字符串需要比較值是否相等的時(shí)候,需要使用equals()方法。并且equals方法的左邊最好是確定不為空或者字符串的字面值。防止出現(xiàn)NullPointException異常。

? ? ? ? 結(jié)束語:

? ? ? ? 本文從八大基本類型和其包裝類,以及String對(duì)象分析==字符在Java中的應(yīng)用判斷情況,相信通過本篇文章的閱讀,可以使你如同文章標(biāo)題一樣,全面搞定==符號(hào)。當(dāng)然這也是我寫這篇文章的目的,感謝您能看到最后。

????????方便自己,也方便他人,堅(jiān)持原創(chuàng)!

????????文章來源地址http://www.zghlxwxcb.cn/news/detail-715575.html

到了這里,關(guān)于一篇文章帶你徹底弄懂Java的==符號(hào)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包