1. 程式人生 > >Effective Java -- 重寫equals方法的通用約定(一)

Effective Java -- 重寫equals方法的通用約定(一)

equals() 方法是Object 類的一個非final 方法,在重寫改類的時候我們應該遵循一下五種通用約定:

  • 自反性:對於任何的非null 的引用值 x ,那麼 x.equals(x) 的返回值一定為true
  • 對稱性:對於任何的非空的引用值 xy ,則x.equals(y)y.equals(x) 的返回值是同真同假的。
  • 傳遞性:對於任何非空的引用值xyz ,如果x.equals(y) 的返回值為true,並且y.equals(z) 的返回值也是true,那麼對應的有x.equals(z) 的值也必須為true
  • 一致性:對於任何非空的應用值xy,只要x.equals(y)
    的返回值為true(或false),那麼在沒有修改的情況下,無論呼叫多少次,其結果依然是true(或false)。
  • 對於任何非空的引用值x,那麼有x.equals(null) 的返回值就一定是false

今天在這裡我們就著重看一下重寫equals() 方法時候要滿足的性質——對稱性

總所周知,在Linux的檔案系統中的檔名稱是區分大小寫的,而在Windows的檔案系統中的檔名是不區分大小寫的,這也就是說abcAbC 是相等的。

所以我們現在需要一個儲存windows作業系統檔名稱的類,這就是說,其對應的判斷檔名的方法是忽略大小寫的。

package com.blog.effective.note8part1;

/**
 * 〈windows作業系統的檔名〉<br>
 *
 * @author
未緒 * @time 2017/12/17 9:18 */
public class WindowsFileName { private String fileName; //檔名稱 public WindowsFileName(String fileName) { this.fileName = fileName; } @Override public boolean equals(Object obj) { //如果穿傳過來的是 WindowsFileName if(obj instanceof
WindowsFileName){ return fileName.equalsIgnoreCase(((WindowsFileName) obj).fileName); } //如果穿過來的是檔名 if(obj instanceof String){ return fileName.equalsIgnoreCase((String)obj); } return false; } }

測試一下其是否滿足傳遞性

package com.blog.effective.note8part1;

/**
 * 〈覆equals方法的時候應該注意的問題〉<br>
 *
 * @author 未緒
 * @time 2017/12/17 8:32
 */
public class MyEqualsDemo1 {


    public static void main(String[] args) {

        WindowsFileName windowsFileName=new WindowsFileName("F:\\test");
        String fileName="F:\\TEST";

        System.out.println(windowsFileName.equals(fileName));   //true
        System.out.println(fileName.equals(windowsFileName));   //false

    }
}

可知該方法是違反了傳遞性的。

那麼這樣寫有什麼危害呢?

如下的例子,如果我們想將windowsFileNamefileName 同時加入到ArrayList 中儲存起來,這時候就會發現我們在WindowsFileName 中重寫的equals() 方法惹了大麻煩了。

如下程式碼輸出false

        List<Object> list=new ArrayList<>();
        list.add(windowsFileName);
        System.out.println(list.contains(fileName));//fasle

而如果我們改變插入的順序,則結果就變得不同了,如下會輸出true

        List<Object> list=new ArrayList<>();
        list.add(fileName);
        System.out.println(list.contains(windowsFileName));//true

這樣當然不是我們想要的結果,程式就會變得非常的不穩定,系統可能會莫名其妙的報錯。

我們將上面的WindowsFileName 類中重寫的 equals() 方法稍微修改一下,這樣就可以滿足傳遞性了:

    @Override
    public boolean equals(Object obj) {
        //如果穿傳過來的是 WindowsFileName
        if(obj instanceof   WindowsFileName){
            return fileName.equalsIgnoreCase(((WindowsFileName) obj).fileName);
        }
        return false;
    }

以上就是有關重寫Object 類中的 equals() 方法要滿足傳遞性的相關內容了。

注意:這裡和是否滿足大小寫沒有啥關係,主要是重寫的equals() 方法可以接受String 型別的引數使其違反了傳遞性。