为什么 Set 在这里允许重复?

Why does Set allow a duplicate here?

我有以下代码:

class Animal {
    int i;

    public Animal(){
        i=13;
    }

    public String toString(){
        return "Animal "+i;
    }
}
//
public class NewMain {
    public static void main(String[] args) {
        HashSet hs=new HashSet();
        boolean b=hs.add(new Animal());
        boolean b1=hs.add(new Animal());
        System.out.println(b+" "+b1);
        for(Object o:hs)
        {
            System.out.println(hs);
        }
    }
}

我知道Set不允许重复,但为什么上面的代码似乎允许两个相同的值?

因为Java无法知道你的两个实例是一样的。

您需要覆盖 equals() hashcode() .

您尚未覆盖 Animal class 中的 hashcodeequals。因此,这些方法都是继承自java.lang.Object.

继承的行为(来自 Object)是对象只有在它们是同一对象时才相等。

在这种情况下,equalshashcode 的一对合适的覆盖应该是这样的:

  @Override
  public boolean equals(Object other) {
      return other instanceof Animal && 
             other != null &&
             ((Animal) other).i == this.i;
  }

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

(请注意,如果您开始创建 Animal 的子 class,您需要仔细考虑如何最好地实现 equals(Object)。上面的代码不会尝试处理那个...)

如前所述,您需要覆盖 hashCodeequals。您可以将 int i

之类的内容进行比较
class Animal {
    int i;

    public Animal() {
        i = 13;
    }

    @Override
    public String toString() {
        return "Animal " + i;
    }

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

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Animal) {
            return ((Animal) obj).i == i;
        }
        return false;
    }
}

那么我建议您在 Collection 中使用泛型。此外,您应该在循环中打印实例(而不是 Collection)。像,

public static void main(String[] args) {
    Set<Animal> hs = new HashSet<>();
    boolean b = hs.add(new Animal());
    boolean b1 = hs.add(new Animal());
    System.out.println(b + " " + b1);
    for (Animal a : hs) {
        System.out.println(a);
    }
}

然后我得到(预期的)

true false
Animal 13