2008-12-12 36 views
11

在我的項目上運行FindBugs時,出現了上述錯誤的幾個實例。Findbugs警告:Equals方法不應該假定任何關於其參數的類型

也就是說,我的重寫版本的equals將RHS對象強制轉換爲與定義覆蓋版本的對象相同的類型。

但是,我不確定是否有更好的設計是可能的,因爲AFAIK Java不允許在方法參數上有差異,所以不可能爲equals參數定義任何其他類型。

我做的事情非常錯誤,還是FindBugs太渴望?

解釋這個問題的另一種方式是:如果傳遞給equals的對象與LHS的類型不是同一類型,那麼正確的行爲是什麼:這是假的,還是應該有異常?

例如:

public boolean equals(Object rhs) 
{ 
    MyType rhsMyType = (MyType)rhs; // Should throw exception 
    if(this.field1().equals(rhsMyType.field1())... // Or whatever 
} 
+0

這聽起來有點奇怪。請給我們看一些代碼。 – 2008-12-12 23:11:12

回答

27

通常情況下,執行等於您可以檢查類的說法是否等於(或兼容)實現類鑄造前時。類似這樣的:

if (getClass() != obj.getClass()) 
    return false; 
MyObj myObj = (MyObj) obj; 

這樣做可以防止FindBugs警告。

一個側面說明,以解決評論:
有些人認爲使用instanceof而不是getClass檢查類型安全。有一個很大的爭議,我試圖不進入,當我注意到,你可以檢查類相等兼容性,但我想我不能逃避它。歸結起來,如果你使用instanceof你可以支持一個類的實例和它的子類的實例之間的平等,但是你冒險打破equals的對稱合約。一般我會建議不要使用instanceof,除非你知道你需要它,並且你知道你在做什麼。欲瞭解更多信息,請參閱:

+4

基本上這意味着什麼:而不是拋出一個ClassCastException,你的equals()方法應該返回false。 – Darron 2008-12-12 23:13:35

+0

但是這種情況下的正確做法是什麼?我的意思是,理想情況下我會喜歡編譯時類型檢查,由於Java限制,我無法獲得該檢查。 – Uri 2008-12-12 23:15:14

7

你可能做這樣的事情:

public class Foo { 
    // some code 

    public void equals(Object o) { 
    Foo other = (Foo) o; 
    // the real equals code 
    } 
} 

在這個例子中我們假定你是一些關於equals()方法的參數:假定你是它的Foo類型。這不是這種情況!你也可以得到一個字符串(在這種情況下,你幾乎肯定會返回false)。

所以,你的代碼應該是這樣的:

public void equals(Object o) { 
    if (!(o instanceof Foo)) { 
    return false; 
    } 
    Foo other = (Foo) o; 
    // the real equals code 
} 

(或使用由Dave L.提到的更嚴格的getClass() != o.getClass()

你也可以看看這樣說:

Integer i = new Integer(42); 
String s = "fourtytwo"; 
boolean b = i.equals(s); 

是否有任何理由認爲此代碼應該拋出ClassCastException而不是正常結束並將b設置爲false

投擲ClassCastException作爲對.equals()的響應將是不明智的。因爲即使它是一個愚蠢的問題(「當然一個字符串永遠不會等於一個Foo!」),它仍然是一個有效的答案(「no」== false)。

0

我開始我的equals(對象)實現這樣的:

if ((object == null) || !(object instaceof ThisClass)) { 
    return false; 
} 

這也將防止FindBugs的警告,但是當ThisClass的一個子類中被移交不會自動返回false這也可能被考慮。相等,特別是如果它的equals(Object)方法沒有被覆蓋。

1

我建議忽略所述findbugs警告。在實踐中,如果用一個意想不到的類的對象調用equals,那幾乎肯定是一個錯誤,並且你想要在錯誤上快速失敗。例如,如果你有一個'ArrayList文件'並且調用files.contains(「MyFile.txt」),那麼如果你有一個ClassCastException,那將會很不錯。相反,Java只是返回false,並且可能需要很長時間纔會發現該錯誤。

相關問題