Почему set не позволяет дублировать значение, какой механизм используется за ними?

Я новичок в Java, я знаю set не допускается дублирование значения но я не знаю почему set не разрешено дублировать значение на самом деле, я делаю практически,

объявлен один набор и добавить повторяющееся значение, но не происходит никакой ошибки, нет ошибки времени компиляции, нет времени выполнения. почему?

10 ответов


значение "наборы не позволяют дублировать значения" заключается в том, что при добавлении дубликата в набор дубликат игнорируется, а набор остается неизменным. Это не приводит к ошибкам компиляции или выполнения: дубликаты молча игнорируются.

вы можете сказать, что значение является дубликатом, проверив результат 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 сохранить элемент с помощью HASHTABLE ...HASHTABLE - это структура пар ключевых значений..Вот какие значения передавал SET рассматривается как ключи HASHTABLE внутренне. ключи уникальны, их нельзя дублировать. Именно по этой причине, если вы передаете любое повторяющееся значение, оно возвращает false и не добавляется в SET ...

Если добавляющий элемент возвращает true, он будет добавлен в SET...Иначе он вернет False, поэтому он не даст никакой компиляции или ошибки выполнения, и он не будет добавлен в SET


Set не разрешено хранить дублированные значения по определению. Если вам нужны дублированные значения, используйте список. Как указано в документации по интерфейсу, при попытке добавления дублированного значения используется метод add возвращает false, не является исключением.

http://docs.oracle.com/javase/7/docs/api/java/util/Set.html


Set (Документация Oracle)

коллекция, не содержащая повторяющихся элементов. Более формально, множества не содержат пары элементов e1 и e2 таких, что e1.равно (e2) и не более одного нулевого элемента. Как следует из его названия, этот интерфейс моделирует абстракцию математического множества.

см.:http://docs.oracle.com/javase/7/docs/api/java/util/Set.html

установить (математики АН) - цитирую Википедия

в математике множество представляет собой набор различных объектов, рассматриваемых как самостоятельный объект.

Добавить Способ

согласно документации интерфейса, если элемент не существует, он добавляется. Иначе ничего не изменится.

логическое добавить(E e):

добавляет указанный элемент в этот набор, если он еще не присутствует (необязательная операция). Если этот набор уже содержит элемент call оставляет набор без изменений и возвращает false.

Пример Кода Реализации: HashSet

 /**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

в дополнение к вышеприведенным ответам, вот почему set не позволяет дублировать элементы:

когда вы вызываете add (E e), метод set, он внутренне вызывает метод put(E, e) HashMap, который выглядит примерно так :

 public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

следовательно, элемент, который вы добавляете в set / HashSet, внутренне добавляется в Map в качестве ключа. Поскольку нам нужно связать некоторое значение с ключом в so dummy value (new Object ()) PRESENT передается каждый раз (поскольку карта может содержать более одного дубликата значения.)

теперь, если вы внимательно изучите return map.put(e, PRESENT)==null; метода add (e, E). Существует две возможности:

  1. если карте.put (k,v) возвращает null, затем map.put(e, PRESENT)==null; вернет true и элемент будет добавлен.
  2. если карте.put (k,v) возвращает старое значение для ключа, затем map.put(e, PRESENT)==null; возвращает false и элемент не будет добавлен.

надеюсь, что это поможет в понимании ясно.


благодаря A2A..

когда вы передаете дубликат элемента в методе add объекта set, он возвращает false и не добавляет его в набор, поскольку элемент уже присутствует.

Set<Object> set = new HashSet<Object>();
set.add("test");
set.add("test");

если вы посмотрите на реализацию HashSet, то это выглядит следующим образом.

public HashSet() {
        map = new HashMap<>();
    }

означает, что HashSet внутренне создает объект HashMap.

public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

если вы посмотрите на параметр метода add e, то ваше переданное значение (тест) будет рассматриваться как ключ на карте и настоящее-это фиктивный объект, переданный как значение.

метод HashMap put возвращает следующее

 1. null, if the key is unique and added to the map
 2. Old value of the key, if key is duplicate

Итак, когда вы добавляете тестовый элемент в первый раз, HashMap добавит элемент и вернет null после этого ваш метод add набора вернет true. Если вы добавите тестовый элемент во второй раз, то ваш HashMap вернет старое значение ключа, а затем в методе add вашего набора вернет false как OldValue != null

Надежда это будет полезно..!!


таким образом, хорошо известно, что Set не позволяет дублировать или равные объекты, но равенство объектов будет заботиться программист, давая желаемую реализацию методов equals() и hashCode (). если мы не реализуем эти два метода, набор даже позволит дубликаты также. В коллекциях на основе хэша в java сначала вызывается метод hashCode (), а затем метод equals (), вызываемый при необходимости для проверки равенства объектов. , поэтому нижняя линия установлена с помощью Map функциональность внутренне и установленные значения вставляются как ключи внутри этой карты внутренне, и карта не позволяет дублировать ключи, Вы также можете проверить HashSet.класс java из Java API, где вы можете найти аналогичную карту, которая на самом деле делает все вещи.

вот небольшой пример кода:

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

"набор-это набор различных объектов"... http://en.wikipedia.org/wiki/Set_%28mathematics%29

при создании набора в нем могут быть только уникальные объекты по определению. Добавление одного и того же объекта дважды не изменяет набор, поскольку элемент/объект уже находится в наборе. Это ожидаемое поведение. Пример, когда это поведение полезно, - это когда нужно найти уникальные элементы из коллекции элементов (т. е. удалить дубликаты).


потому что именно так определяются наборы. Элемент может существовать только один раз в наборе, но это не означает, что попытка добавить его во второй раз должна быть ошибкой. Это просто не операция. Это довольно ясно из документации, например, для Set#add:

добавляет указанный элемент в этот набор, если он еще не присутствует (необязательная операция). ... Если этот набор уже содержит элемент, вызов оставляет набор без изменений и возвращает false. В в сочетании с ограничением конструкторов это гарантирует, что наборы никогда не содержат повторяющихся элементов.

среди прочего, это позволяет вам с радостью добавлять в наборы, не беспокоясь, и знать, что результат будет иметь только уникальные значения.

объявлен один набор и добавить повторяющееся значение, но не происходит никакой ошибки, нет ошибки времени компиляции нет времени выполнения. Почему?

потому что это не ошибка. Но заметьте, что вы сделал (или мог бы) получил указание на то, что значение уже присутствует:add возвращаемое значение метода (см. ссылку выше) говорит вам:"true если этот набор уже содержит элемент"!--19-->


из документации, вы можете сделать следующее:

добавляет указанный элемент e в этот набор, если набор не содержит элемента e2 такой, что (e==null ? e2==null : e.equals(e2)). Если этот набор уже содержит элемент, дубликат игнорируется, оставляет набор неизменным и возвращает false. Это гарантирует, что наборы не содержат повторяющихся элементов.

boolean add(E e): метод возвращает true, если набор еще не содержит указанный элемент.

он выбрасывает следующие типы исключения:

UnsupportedOperationException - если операция добавления не поддерживается этим набором

ClassCastException - если класс указанного элемента предотвращает его добавление в этот набор

NullPointerException - если указанный элемент равен null и этот набор не разрешает null элементы

IllegalArgumentException - если некоторое свойство указанного элемент предотвращает его добавление в этот набор