Set应该只包含不可变元素吗?

时间:2017-02-28 17:54:44

标签: java

我有SetA类型的元素。

如果我修改了Set中包含的元素(考虑到这个修改可能会改变任何a的身份),我的代码会闻到吗?

4 个答案:

答案 0 :(得分:3)

例如,一个问题是,如果您向集合添加A a,然后以更改其哈希码的方式变更aset.contains(a)将有可能返回false。

琐碎的例子:

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; }
}

答案 1 :(得分:1)

由于您可以通过修改内部的可变元素来中断package de.poller.StorrageBox; import java.awt.CardLayout; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class MainClass implements KeyListener { JFrame frame; JPanel panel; JPanel panel1; JPanel panel2; public static void main(String[] args) { MainClass c=new MainClass(); } public MainClass() { frame=new JFrame("test"); frame.setSize(new Dimension(500, 500)); frame.addKeyListener(this); panel=new JPanel(new CardLayout()); frame.add(panel); panel1=new JPanel(); JButton butt1=new JButton("test1111"); panel1.add(butt1); panel2=new JPanel(); JButton butt2=new JButton("test222"); panel2.add(butt2); panel.add(panel1,"1"); panel.add(panel2,"2"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); frame.requestFocus(); } public void keyPressed(KeyEvent arg0) { if(arg0.getKeyChar()=='a') { activate1(); } if(arg0.getKeyChar()=='b') { activate2(); } } private void activate2() { CardLayout cl=(CardLayout)(panel.getLayout()); cl.show(panel, "2"); } private void activate1() { CardLayout cl=(CardLayout)(panel.getLayout()); cl.show(panel, "1"); } public void keyReleased(KeyEvent arg0) {} public void keyTyped(KeyEvent arg0) {} } ,因此,immutable肯定是首选

答案 2 :(得分:1)

大多数情况下,一个集合应该只包含不可变量。

来自the JavaDoc of the Set interface

  

注意:如果将可变对象用作集合元素,必须非常小心。如果在对象是集合中的元素时以影响等于比较的方式更改对象的值,则不指定集合的行为。这种禁止的一个特例是,不允许集合将自己作为一个元素包含在内。

强调我的。

如果您能够在不影响equals()的情况下修改元素,我会强烈重新考虑您的equals实现是否正确。

答案 3 :(得分:0)

它很可能闻起来,因为如果修改了一个也用于计算hashCode的字段,则Set会中断。

因此,对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;
    }
    }
}