日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【JAVA基础】一:聊聊笔试常见到的 “==、equal” 比较是否相等的内在差别

發(fā)布時間:2023/11/29 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【JAVA基础】一:聊聊笔试常见到的 “==、equal” 比较是否相等的内在差别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

開始本文之前,先讓我們記住一個口訣(這個口訣只針對基礎的類比如String、Integer等,如果是自定義的類,需要看equal的具體實現(xiàn)):
equal比較其值,== 比較地址

這兩天在走查代碼的時候發(fā)現(xiàn)一個童鞋,在判斷兩個Integer類型的值是否相等的時候,用了==來判斷,運行結果沒錯,因為這兩個值在-128~127之間。 只是這種寫法不符合規(guī)范,有隱患,我不是挑刺,但是覺得有必要給出個所以然來為啥要按照規(guī)范使用equal來比較對象值是否相等。

讓我們先來看個筆試的例子:請問寫出下面的代碼輸出結果。

public class JavaTest {public static void main(String args[]){Integer a = 127;Integer b = 127;Integer c = new Integer(127);Integer d = new Integer(127);int e = 127;// 1System.out.println(a == b);// 2System.out.println(a.equals(b));// 3System.out.println(a == c);// 4System.out.println(a.equals(c));// 5System.out.println(a == e);// 6System.out.println(a.equals(e));a = 200;b = 200;// 7System.out.println(a == b);// 8System.out.println(a.equals(b));} }

答案是:
true
true
false
true
true
true
false
true

運用口訣:equal比較其值,==比較地址
第12行輸出:true;因為它們的引用地址是同一個,這個地址存的值是127。
第14行輸出:true;因為它們的值都是127,所以equal比較其值,結果是相等。
第16行輸出:false;因為它們兩個對象的引用地址不一樣。
第18行輸出:true;同上面的第2處。
第20行輸出:true;這里會把e做裝箱操作(從基本類型提升為包裝對象類型),之后它們的引用地址是同一個,同第1處,后面解析java裝箱、拆箱的概念。
第22行輸出:true;此處一樣會對e裝箱提升為Integer對象,然后它們的值都是127,所以equal結果為true。
第28行輸出:false;因為它們的引用地址不一樣,它們不一樣~,跟第1處不一樣…下面會講解。
第30行輸出:true;因為它們的值都是200,同前面第2、4、6。

  • 前面講到java自動裝箱、拆箱 ,簡單點說,裝箱就是把基本類型升級為對象包裝類型;拆箱就是把對象包裝類型轉換為對應的基本類型。

會自動拆箱、裝箱的數(shù)據(jù)類型為:

對象類型基本類型
Integerint (4字節(jié))
Shortshort (2字節(jié))
Floatfloat (4字節(jié))
Doubledouble (8字節(jié))
Bytebyte (1字節(jié))
Longlong (8字節(jié))
Characterchar (2字節(jié))
Booleanboolean (未定)

下面讓我們來看下具體的裝箱、拆箱過程:我們編寫一個Test類文件保存在Test.java文件中,UTF-8編碼存儲,內容如下:

public class Test{public static void main(String[] args) {// 裝箱Integer numInteger = 120;// 拆箱int num_int = numInteger;} }

我們編譯一下:

javac Test.java

如果提示“GBK編碼…”之類的錯誤,在指令加個編碼選項:

javac -encoding utf-8 Test.java

然后會在當前目錄生成一個Test.class文件,我們通過javap工具反匯編看下這個class的內容:

javap指令這里就不展開了,感興趣的可以看文檔:Javap官方文檔

javap -c Test.class

上面的指令會直接顯示反編譯的內容,或者你也可以通過下面的指令來把反匯編的內容輸出到文件中,比如輸出當前目錄的Test.bin文件里面:

javap -c Test.class>Test.bin

反匯編的內容如下:

Compiled from "Test.java" public class Test {public Test();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: bipush 1202: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;5: astore_16: aload_17: invokevirtual #3 // Method java/lang/Integer.intValue:()I10: istore_211: return }

執(zhí)行第6行代碼Integer numInteger = 120;時,系統(tǒng)底層是執(zhí)行了Integer.valueOf 來把數(shù)值120轉換為一個新的Integer包裝對象類型。

執(zhí)行第9行代碼int num_int = numInteger;的時候,系統(tǒng)底層實際是執(zhí)行了Integer.intValue 來把包裝對象numInteger的intValue值取出來賦值給int類型變量num_int:

  • 那前面的JavaTest類中第12行跟28行的結果為啥不一樣?
Integer a = 127; Integer b = 127;// 1、結果為true System.out.println(a == b);a = 200; b = 200;// 7、結果為false System.out.println(a == b);

感覺有點坑吧?我覺得出這個題目的考官是不是有點刁鉆呀… 這個并沒有啥神秘的,我們直接看源碼吧。

當代碼中第1處的括號運算:a == b的時候 ,根據(jù)口訣,是判斷這兩個包裝對象的地址是否一樣,根據(jù)上面的反匯編代碼可以看出來,代碼中的Integer a = 127;對應的操作是Integer a = Integer.valueOf (127); Integer類的源碼的valueOf如下:

public final class Integer extends Number implements Comparable<Integer> {// ....../*** Cache to support the object identity semantics of autoboxing for values between* -128 and 127 (inclusive) as required by JLS.** The cache is initialized on first usage. The size of the cache* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.* During VM initialization, java.lang.Integer.IntegerCache.high property* may be set and saved in the private system properties in the* sun.misc.VM class.*/private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint 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_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;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() {}}/*** Returns an {@code Integer} instance representing the specified* {@code int} value. If a new {@code Integer} instance is not* required, this method should generally be used in preference to* the constructor {@link #Integer(int)}, as this method is likely* to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since 1.5*/public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}// ...... }

從上面的源碼可以看出來,對于-128 ~ 127之間(閉包)的int值,通過valueOf得到其對應的Integer對象,是已經預先靜態(tài)生成好的存放在數(shù)組中的對象,所以只要這個int值是在這區(qū)間范圍的,得到的對象都是同一個。而如果傳過來的int值不在 -128 ~ 127 區(qū)間范圍,直接在最后new 一個新的Integer對象返回的,這就解釋了為啥兩個自動裝箱數(shù)值為200的對象,用==來判斷其地址,是不一樣的,因為兩個對象都不一樣了。

這里JDK應該是對于這些1字節(jié)長度的數(shù)值,總共28 = 256個,從-128~127,預先存起來,加快包裝的速度、節(jié)省存儲空間。那為啥不把兩個字節(jié)、三個字節(jié)的都預先存起來呢?who knows?… 那為啥不把float、double的值也存起來?這兩種類型的區(qū)間數(shù)是無限的好嗎,看官你別逗了…

綜上所述:

  • == 對于基本類型的數(shù)值,是比較它們的值是否相等;對于包裝對象這種引用型的變量,比較的是它們在堆中存儲的地址是否相同。
  • equals 表示這兩個變量的value數(shù)值是否相同。

如果是自定義的類調用equal,這個需要具體看此類的equal有沒有重寫,具體如何實現(xiàn)的,比如:

public class Test extends Object{int num = 0;public Test(int i){this.num = i;}public static void main(String[] args) {Test t1 = new Test(1);Test t2 = new Test(1);System.err.println(t1.equals(t2));System.err.println(t1 == t2);} }

上面的程序執(zhí)行輸出為:
false
false

第二個是false,這個很容易理解,但是第一個為啥呢,不是說好了equal是比較值么?但是這個Test自定義類并沒有重寫equal方法,所以調用的是Object里面的equal,我們看下它的源碼:

也就是,Object的equal實現(xiàn)默認還是通過 == 來實現(xiàn)的… 明白了吧,所以我們自己來實現(xiàn)equal如下:

public class Test extends Object{int num = 0;public Test(int i){this.num = i;}@Overridepublic boolean equals(Object obj) {if(!(obj instanceof Test) || null == obj){return false;}return (num == ((Test) obj).num);}public static void main(String[] args) {Test t1 = new Test(1);Test t2 = new Test(1);System.err.println(t1.equals(t2));System.err.println(t1 == t2);} }

這樣,就能實現(xiàn)equal比較的是值了,跟前面的口訣保持一致了。

轉載于:https://www.cnblogs.com/xiaocy66/p/10589257.html

總結

以上是生活随笔為你收集整理的【JAVA基础】一:聊聊笔试常见到的 “==、equal” 比较是否相等的内在差别的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。