2010-06-10 99 views
9

我有一個接口,我希望實現此接口的每個人都實現一個覆蓋「equals」方法。在接口中強制執行「等於」

有沒有辦法確保發生?

我想這會發生的方式是,實現我的接口的類將自動從Object中獲取equals,因此使接口很高興。

+1

你對此的理由是什麼? – 2010-06-10 06:44:40

+0

遇到這個問題時遇到的具體情況; 我有一個接口,實現了幾個類。這些類是由唯一的標識符標識的。所以如果兩個標識符是相同的,則應該認爲這些對象是平等的。 有一次,我有一個這些類的列表,並想知道如果一個新的對象已經存在於列表中。 我認爲這將是優雅的List.contains(..)用於此檢查。但是這要求我可以肯定等於被覆蓋。 雖然易於以其他方式解決。抽象類也可以運行得很好。 – Fredrik 2010-06-10 11:06:05

回答

10

沒有,你只可以創造的,而不是像這樣的接口的抽象類:

public abstract class MyApi { 

    public final boolean equals(Object other) { 
    if (other == this) { 
     return true; 
    } 
    if (other instanceof MyApi) { 
     return equals((MyApi)other); 
    } 
    return false; 
    } 

    protected abstract boolean equals(MyApi other); 

} 

或者更簡單的版本:

public abstract class MyApi { 

    public boolean equals(Object other) { 
    throw new UnsupportedOperationException("equals() not overridden: " + getClass()); 
    } 

} 

編輯(給它後一試來自@CodeConfident的評論,謝謝!永遠不會假定它會起作用):

您也可以簡單地在ab中聲明equals()加強海峽類(!不是一個接口),因此隱藏Object實施和任何子類強制執行新的實現:

public abstract class MyApi { 

    public abstract boolean equals(Object obj); 

    public abstract int hashCode(); 

} 

反正你應該始終貫徹equals()hashCode()一起履行合同。

+0

如果您主張使用抽象類,爲什麼不聲明equals(Object)是抽象的? – ILMTitan 2010-06-10 14:33:08

+2

@ilmtitan:你不能聲明一個繼承的方法摘要! – 2010-06-10 17:39:39

+0

@ArneBurmeister - 這是不正確的(現在至少)。您絕對可以在抽象類中使用抽象方法重寫繼承的方法。看到這個答案︰https://stackoverflow.com/questions/1718112/tostring-equals-and-hashcode-in-an-interface#answer-1718170 – AjahnCharles 2017-07-20 07:08:42

3

不可以。您可以將它添加到接口(以及javadocs),但是如果Object.equals具有相同的簽名,則不能讓編譯器使它們覆蓋它。

1

編輯:可能不是一個好主意(請參閱FarmBoy的評論)。留在這裏爲後人。

而不是使用Object類中的equals(Object obj),使它們與接口的實現進行比較。

public interface MyInterface { 
    public boolean equals(MyInterface mi); 
} 

因此,

public class MyImplementation implements MyInterface { 
    public boolean equals(MyInterface mi) 
    { 
    if(this == mi) 
     return true; 
    // for example, let's say that each implementation 
    // is like a snowflake...(or something) 
    return false; 
    } 
} 

然後:

public class Main { 

    public static void main(String[] args) 
    { 
    Object o = new MyImplementation(); 
    MyImplementation mi1 = new MyImplementation(); 
    MyImplementation mi2 = new MyImplementation(); 

    // uses Object.equals(Object) 
    o.equals(mi1); 
    // uses MyImplementation.equals(MyInterface) 
    mi1.equals(mi2); 
    // uses Object.equals(Object) 
    mi2.equals(o); 
    } 
} 
+2

這不是一個好主意。任何調用相等的東西(比如把一個對象放到一個'Set'中不會調用這個等於,而是'真正'),所以你會迫使實現類實現這個方法,任何好的程序員都會實現'真正'的 – 2010-06-10 06:35:09

+0

好點 - 我沒有想過這個問題,我想從提問者那裏得到更多關於這個問題背後動機的細節。 – Catchwa 2010-06-10 06:39:37

0

我猜有可能是爲什麼方法可能需要

  1. 希望這樣的等於兩個原因確保所有的課程你的應用程序(或其子集)「將」具有equals方法。就像標準執行一樣,或者確保你使用的某些API能夠正常工作(並且他們期望等於正確實現)。假設你使用Maps的次數很多,並且希望絕對確定一些類的子集絕對可能映射鑰匙) 如果是這樣,這不是要走的路。在這種情況下,你將無法做到這一點,但即使你是這樣,也是不正確的。您應該使用代碼覆蓋工具,並進行更好的單元測試。

  2. 你不想要等於方法,但想要一個類似的方法。在這種情況下,您可以在界面中創建另一個具有相似名稱的方法。

3

的接口是低保方法存在合同。

沒有強制執行該方法的機制應該在接口中被覆蓋。

0

我已經嘗試在JavaDoc中編寫equals所需的合同。但hashCodeequals一致的要求導致hashCode的複雜合同。所以我放棄了,用兩個方法的final實現來創建抽象基類。