2017-02-28 100 views
-1

我有一個SetA類型的元素。一個集合應該只包含不可變元素嗎?

如果我修改集合中包含的元素(考慮到這種修改可能會改變任何a的身份),我的代碼是否有異味?

+6

它不只是聞。它打破了。 –

+1

取決於哪些字段用於計算hashCode/equals以及哪些字段被修改。 – kerner1000

回答

1

大多數時候一組應該只包含immutables。

the JavaDoc of the Set interface

注意:如果使用可變對象作爲一組元素大,一定要小心。沒有指定集合的行爲如果對象的值以影響等於比較的方式更改,而對象是集合中的元素,則該對象的值會發生更改。這種禁令的一個特例是,一個集合不允許自己作爲一個元素。

強調我的。

如果您能夠在不影響equals()的情況下修改元素,我會強烈重新考慮您的等值實現是否正確。

+0

如果程序員編寫調用它的代碼並不會讓任何程序員驚訝,那麼'equals()'的實現就是_correct_。 (這並不意外,任何程序員都會在Set中使用你的類的成員。)如果你是唯一一個會使用你的類編寫代碼的人,那麼你的意見是唯一重要的。另一方面,如果您打算讓您的代碼被其他人重新使用,那麼您可能想要更加認真地考慮其他人期望「equals()」的含義。 –

+0

我不同意。我相信任何'equals'的實現都應該比較每個字段。這是將被普遍理解的* only *實現。如果你想比較一個對象字段的子集,你應該添加另一個明智的命名方法:'isSamePlaceAs()','isSameSizeAs()'等。 – Michael

1

由於您可以通過修改裏面的可變元素來打破Set,所以不可變的肯定是首選

3

一個問題,舉例來說,就是如果你添加一個A a一組,然後在改變其哈希碼,有一個機會,set.contains(a)將返回錯誤的方式發生變異a

簡單的例子:

public static void main(String[] args) { 
    Set<A> set = new HashSet<>(); 
    A a = new A(1); 
    set.add(a); 
    System.out.println(set.contains(a)); //true 
    a.i = 2; 
    System.out.println(set.contains(a)); //false 
} 

static class A { 
    int i; 
    public A(int i) { this.i = i; } 
    @Override public int hashCode() { return i; } 
} 
+0

一個假設你的例子假定一個相應的'equals'實現,即使你沒有顯示它。 –

+0

@LewBloch這個例子不需要工作,但是一般情況下你也可以重寫'equals'。 – assylias

+0

如果'equals'方法返回錯誤的答案,那麼'Set'如何找到該項目?是的,這個例子是必需的。請記住,哈希集合既使用'hashCode'也使用equals。如果它們不一致,代碼就會中斷。實際上,你聲稱破碎的代碼是可以接受的。 –

0

它最有可能聞起來,因爲如果一個字段被修改,也被用來計算hashCode,Set打破。因此可以打破Set

相反,修改List中的元素將永遠不會破壞該列表。

簡單的例子(截斷並從assylias擴展回答)

public class Main { 

    public static void main(String[] args) { 
    Set<A> set = new HashSet<>(); 
    List<A> list = new ArrayList<>(); 
    A a = new A(1); 
    set.add(a); 
    list.add(a); 
    System.out.println(set.contains(a)); // true 
    System.out.println(list.contains(a)); // true 
    a.i = 2; 
    System.out.println(set.contains(a)); // false 
    System.out.println(list.contains(a)); // true 
    } 

    static class A { 
    int i; 

    public A(int i) { 
     this.i = i; 
    } 

    @Override 
    public int hashCode() { 
     return i; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj == null) { 
     return false; 
     } 
     if (!(obj instanceof A)) { 
     return false; 
     } 
     A other = (A) obj; 
     if (i != other.i) { 
     return false; 
     } 
     return true; 
    } 
    } 
} 
+0

假設你的例子假定你有相應的'equals'實現,即使你不要顯示 –

+0

謝謝Lew,固定。 – kerner1000

+0

建議成語:'return i == other.i'。在'if'中使用'boolean'來確定'boolean'有點多餘。 –

相關問題