物件指定與相等性


使用標準 API 類別 的範例中,比較兩個BigDecimal是否相等,是使用equals()方法而非使用==運算子,為什麼?Java並非完全的物件導向程式語言,在Java中有兩大型態系統,基本型態與類別型態,這很令人困擾,若不討論底層記憶體實際運作,初學者就必須區分Java中===運算用於基本型態與類別型態的不同。

當=用於基本型態時,是將值複製給變數,==用於基本型態時,是比較兩個變數儲存的值是否相同,這對初學者來說沒有問題,所以底下的程式片段會顯示兩個true,因為ab儲存的值都是10,而ac儲存的值也都是10:

int a = 10;
int b = 10;
int c = a;
System.out.println(a == b);
System.out.println(a == c);

如果你在操作物件,=是用在指定參考名稱參考某個物件,而==是用在比較兩個參考名稱是否參考同一物件。對初學者來說,通常看不懂這句話是什麼意思,白話來說,=是用在將某個名牌綁到某個物件,而==是用在比較兩個名牌是否綁到同一物件。來看個範例:

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.1");
System.out.println(a == b);        // 顯示false
System.out.println(a.equals(b));  // 顯示true

上面的程式片段,建議初學者以繪圖方式表示,以第一行為例,看到new關鍵字,就是建立物件,那就畫個圓圈表示物件,這個物件內含"0.1",並建立一個名牌a綁到這個新建立的物件,所以第一行與第二行執行後,可用以下的圖來表示:

=用於物件指定的示意圖


程式中使用a == b,就是在問,a牌子綁的物件是否就是b牌子綁的物件?答案「不是」,也就是false的結果,程式中使用a.equals(b),就是在問,a牌子綁的物件與b牌子綁的物件,實際上內含值是否相同,因為ab綁的物件,內含值都是"0.1"代表的數值,答案「是」,也就是true的結果。

再來看一個例子:

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.1");
BigDecimal c = a;
System.out.println(a == b);        // 顯示false
System.out.println(a == c);        // 顯示true
System.out.println(a.equals(b));  // 顯示true

這個程式片段若執行至第三行c = a,表示將a牌子綁的物件,也給c牌子來綁,用圖表示就是:

=用於物件指定的示意圖


所以問到a == b,就是在問ab是否綁在同一物件?結果就是false,問到a == c,就是在問ac是否綁在同一物件?結果就是true,問到a.equals(b),就是在問ab綁的物件實際上內含值是否相同?結果就是true

==
用在物件型態,是比較兩個名稱是否參考同一物件,而!=正好相反,是比較兩個名稱是否沒參考同一物件。實際上,equals()可以自行定義如何比較兩物件的內含值,這將在之後再作說明。

其實從記憶體的實際運作來看, Java中的===並沒有用在基本型態與物件型態的不同,有興趣的話,可以參考 我們沒什麼不同