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 類型的參數使其違反了傳遞性。

發佈了179 篇原創文章 · 獲贊 230 · 訪問量 56萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章