Java 为什么设置不允许重复值,它们背后使用了哪种机制?

Java 为什么设置不允许重复值,它们背后使用了哪种机制?,java,Java,我是java新手,我知道集合不允许重复值,但我不知道为什么集合不允许重复值,实际上我是在实际操作 声明一个集合并添加重复值,但没有发生任何类型的错误,没有编译时错误,也没有运行时错误为什么?因为集合就是这样定义的。一个元素在一个集合中只能存在一次,但这并不意味着尝试第二次添加它应该是错误的。这只是一个禁忌。从文档中可以很清楚地看到,例如: 如果指定的元素尚未存在,则将其添加到此集合(可选操作)。。。如果此集合已经包含元素,则调用将保持集合不变并返回false。结合对构造函数的限制,这可以确保集合

我是java新手,我知道集合不允许重复值,但我不知道为什么集合不允许重复值,实际上我是在实际操作


声明一个集合并添加重复值,但没有发生任何类型的错误,没有编译时错误,也没有运行时错误为什么?

因为集合就是这样定义的。一个元素在一个集合中只能存在一次,但这并不意味着尝试第二次添加它应该是错误的。这只是一个禁忌。从文档中可以很清楚地看到,例如:

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

除此之外,这让您可以轻松地添加到集合中,而无需担心,并且知道结果中只有唯一的值

声明一个集合并添加重复值,但没有发生任何类型的错误,没有编译时错误,也没有运行时错误。为什么?

因为这不是一个错误。但请注意,您确实(或可能)收到了一个指示,表明该值已经存在:
add
方法的返回值(请参见上面的链接)告诉您:“
true
如果此集合尚未包含指定的元素”

“集合不允许重复值”的含义是,当您向集合添加重复值时,重复项将被忽略,且集合保持不变。这不会导致编译或运行时错误:重复项会被忽略

通过检查
add
的结果,可以判断某个值是重复的,如下所示:

Set<String> testSet = new HashSet<String>();
boolean first = testSet.add("hello");
System.out.println(first);             // Prints "true"
boolean second = testSet.add("hello");
System.out.println(second);            // Prints "false"
Set testSet=new HashSet();
boolean first=testSet.add(“hello”);
System.out.println(第一个);//打印“真实”
布尔秒=testSet.add(“hello”);
System.out.println(秒);//打印“假”
Set(Oracle文档) 不包含重复元素的集合。更正式地说,集合不包含e1和e2元素对,因此e1.equals(e2)最多包含一个空元素。正如它的名字所暗示的,这个接口为数学集合抽象建模

见:

集合(数学)-引用自 在数学中,集合是不同对象的集合,它本身被视为一个对象

添加方法 根据接口的文档,如果元素不存在,则添加元素。否则,一切都不会改变

布尔加法(E):

如果指定的元素尚未存在,则将其添加到此集合(可选操作)。如果此集合已经包含元素,则调用将保持集合不变并返回false

示例实现代码:HashSet
/**
*如果指定的元素尚未存在,则将其添加到此集合。
*更正式地说,如果
*此集合不包含元素e2,因此
*(e==null?e2==null:e.equals(e2))。
*如果此集合已经包含该元素,则调用将离开该集合
*未更改并返回false。
*
*@param e要添加到此集合的元素
*@如果此集合尚未包含指定的
*元素
*/
公共布尔加法(E){
返回map.put(e,PRESENT)=null;
}

集合不允许按定义存储重复的值。如果需要重复的值,请使用列表。如接口文档所述,当您尝试添加重复值时,
add
方法返回false,而不是异常

“集合是不同对象的集合”


创建集合时,根据定义,集合中只能有唯一的对象。添加同一对象两次不会更改集合,因为元素/对象已在集合中。这是预期的行为。此行为非常有用的一个示例是,希望从元素集合中查找唯一的元素(即删除重复项).

内部SET使用HASHTABLE存储元素。HASHTABLE是键值对的结构。在这里,SET传递的值在内部被视为HASHTABLE的键。密钥是唯一的,不能重复。这就是如果您传递任何重复值,它将返回false,并且不会添加到集合中的原因


如果adding元素返回true,它将被添加到集合…否则它将返回False,这就是为什么它不会给出任何编译或运行时错误,并且不会被添加到集合

除了上述答案之外,下面是SET不允许重复元素的原因:

当您调用set的add(E)方法时,它在内部调用HashMap的put(E,E)方法,如下所示:

 public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}
因此,要添加到set/HashSet的元素在内部作为键添加到Map中。因为我们需要将一些值与中的键相关联,所以每次都会传递虚拟值(newobject())(因为映射可以包含多个重复值)

现在如果仔细检查
返回映射,put(e,PRESENT)==null。有两种可能:

  • 如果map.put(k,v)返回null,那么
    map.put(e,PRESENT)==null将返回true,并添加元素
  • 如果map.put(k,v)返回键的旧值,则
    map.put(e,PRESENT)==null将返回false,并且不会添加元素
  • 希望这将有助于理解清楚。

    多亏了A2A

    当您在set对象的add方法中传递一个重复的元素时,它将返回false,并且不会将其作为
     public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    
    Set<Object> set = new HashSet<Object>();
    set.add("test");
    set.add("test");
    
    public HashSet() {
            map = new HashMap<>();
        }
    
    public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
    
     1. null, if the key is unique and added to the map
     2. Old value of the key, if key is duplicate
    
    class Employee {
        private static int equalsCounter;
        private static int hashCodeCounter;
        private String name;
        private int age;
    
        public Employee() {
            super();
        }
    
        public Employee(String name, int age) {
            this.name = name;
            this.age = age;
    
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Employee [name=" + name + ", age=" + age + "]";
        }
    
        @Override
        public int hashCode() {
            hashCodeCounter++;
            System.out.println("hashCode() invoked : "+hashCodeCounter+" time");
            final int prime = 31;
            int result = 1;
            result = prime * result + age;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            equalsCounter++;
            System.out.println("equals() invoked: "+equalsCounter+" time");
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Employee other = (Employee) obj;
            if (age != other.age)
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }
    }
    
    public class Main {
    
        public static void main(String[] args) {
            Set<Employee> mySet  = new HashSet<Employee>();
            Employee e1 = new Employee("aaa", 30);
            Employee e2 = new Employee("aaa", 30);
            Employee e3 = new Employee("aaa", 30);
            mySet.add(e1); // HashCode() called and equals() not called
            mySet.add(e2);// HashCode() called and equals() also called
            mySet.add(e3);// HashCode() called and equals() also called
            System.out.println(mySet.size());
        }
    }