java.util.Set中的重复元素

java.util.Set中的重复元素,java,set,Java,Set,java.util.Set实现会删除重复的元素 如何在java.util.Set中内部删除重复元素?阅读您的问题,了解更多详细信息: 您不能从Set.add()的java文档中添加重复项,还是说添加全部?: 如果指定的元素尚未存在,则将其添加到此集合(可选操作)。更正式地说,如果集合中不包含元素e2,则将指定的元素e添加到此集合中(e==null?e2==null:e.equals(e2))。如果此集合已经包含元素,则调用将保持集合不变并返回false。结合对构造函数的限制,这可以确保集合中不包

java.util.Set
实现会删除重复的元素


如何在
java.util.Set
中内部删除重复元素?

阅读您的问题,了解更多详细信息:

您不能从Set.add()的java文档中添加重复项,还是说添加全部?:


如果指定的元素尚未存在,则将其添加到此集合(可选操作)。更正式地说,如果集合中不包含元素e2,则将指定的元素e添加到此集合中(e==null?e2==null:e.equals(e2))。如果此集合已经包含元素,则调用将保持集合不变并返回false。结合对构造函数的限制,这可以确保集合中不包含重复的元素

实际上,大多数java中的
Set
实现都没有检查元素是否已经包含

它们总是在其内部结构上执行
add()
,该结构保存集合元素,并让该对象处理重复情况


e、 g.
HashSet
调用
将(K,V)
放在内部
HashMap
上,如果重复,它只会插入新对象,覆盖旧条目。

读一下你的问题,我猜你看到了
java.util.HashSet
的奇怪行为(通常是每个人默认使用的)

java.util.Set
的约定相反,可以在
java.util.HashSet
中获得相同的对象两次,如下所示:

import java.util.HashSet;
import java.util.Set;

public class SetTest 
{
  public static void main(String[] args) 
  {
    MyClass myObject = new MyClass(1, "testing 1 2 3");

    Set<MyClass> set = new HashSet<MyClass>();
    set.add(myObject);

    myObject.setHashCode(2);
    set.add(myObject);

    System.out.println(set.size());  // this will print 2.
  }

  private static class MyClass 
  {
    private int hashCode;
    private String otherField;

    public MyClass(int hashCode, String otherField) 
    {    
      this.hashCode = hashCode;
      this.otherField = otherField;
    }

    public void setHashCode(int hashCode) 
    {
      this.hashCode = hashCode;
    }

    public boolean equals(Object obj) 
    {    
      return obj != null && obj.getClass().equals(getClass()) && ((MyClass)obj).otherField.equals(otherField);
    }

    public int hashCode() 
    {
      return hashCode;
    }
  }
}
import java.util.HashSet;
导入java.util.Set;
公共类设置测试
{
公共静态void main(字符串[]args)
{
MyClass myObject=新的MyClass(1,“测试1 2 3”);
Set=newhashset();
set.add(myObject);
myObject.setHashCode(2);
set.add(myObject);
System.out.println(set.size());//这将打印2。
}
私有静态类MyClass
{
私有整数哈希码;
私有字符串字段;
公共MyClass(int hashCode,String otherField)
{    
this.hashCode=hashCode;
this.otherField=otherField;
}
public void setHashCode(int hashCode)
{
this.hashCode=hashCode;
}
公共布尔等于(对象obj)
{    
返回obj!=null&&obj.getClass().equals(getClass())&&&((MyClass)obj.otherField.equals(otherField);
}
公共int hashCode()
{
返回哈希码;
}
}
}
在@jitter的指针和源代码之后,您可以看到为什么会发生这种情况

与@jitter一样,
java.util.HashSet
在内部使用
java.util.HashMap
。当散列在第一个和第二个add之间更改时,会在
java.util.HashMap
中使用一个不同的bucket,并且对象会在集合中出现两次


代码示例可能看起来有点做作,但我在域类中看到过这种情况,其中散列是从可变字段创建的,equals方法没有与这些字段保持同步。

找到这一点的简单方法是查找您感兴趣的代码的源代码


每个JDK都包含一个src.zip,其中包含公共类的源代码,因此您可以找到HashSet的源代码并查看:)我经常使用Eclipse来实现这一点。启动它,创建一个新的Java项目,将JVM设置为已安装的JDK(如果不是,您使用的是系统默认的JRE,它没有src.zip),并使用Ctrl-Shift-t转到HashSet。

将指定的元素添加到集合中(如果它还不存在)。
如果集合已经包含元素,则调用将保持集合不变并返回false。再加上对构造函数的限制,这将确保集合从不包含重复的元素。

以修改hashCode()/equals()结果的方式修改HashSet中的对象会产生未定义的行为。@Joachim-准确地说,但这并不意味着它不会发生。事实上,流行IDE生成的equals/hashCode方法通常会导致hashCode随着对象的变化而变化。可以说,如果对象发生变化,hashCode应该变化——毕竟,它需要与
equals()保持一致,因此,如果一个对象不再被视为等同于其突变前的状态,它就需要改变。这里真正的问题是使用可变对象作为HashMap键;强烈建议只使用不可变对象,否则您将面临这种随机性,因为一般来说,
hashCode()
必须随着可变对象的变化而变化。@dtsazza-当对象发生变化时,hashCode不一定需要改变,因为相等的hashCode并不意味着相等(正如上面的例子所示,实例化后更改散列可能是危险的)。
java.util.Set.of(E…elements)
如果发现任何重复项,就会抛出
IllegalArgumentException