Подтвердить что ты не робот

Hashcode и Equals для Hashset

Прошу прояснить мои сомнения в Hashset. Рассмотрим следующий код:

class Person
{
    String name;

    Person(String n)
    {
        name=n; 
    }
    public String getName()
    {
        return name;   
    }

    @Override
    public boolean equals(Object arg0) {

        System.out.println("in equals");

        Person obj=(Person)arg0;

        System.out.println("1st "+getName());
        System.out.println("2nd "+obj.getName());

        if(this.getName().equals(obj.getName()))
        {
                return true;
        }
        return false;
    }


    @Override
    public int hashCode() {

        System.out.println("in hash code");
        System.out.println(" value is "+Integer.valueOf(name.charAt(0)));
        return Integer.valueOf(name.charAt(0));
    }
}

В основном у меня есть следующий код

Person obj1=new Person("bcd");

Person obj2=new Person("cde");

Person obj3=new Person("abc");

Person obj4=new Person("abc");

Теперь, если я добавлю эти объекты в hashset

Set<Person> sset=new HashSet<Person>();

sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj3);

Я получаю этот вывод

in hash code                                                                      
value is 98    
in hash code   
value is 97    
in hash code    
value is 99    
in hash code    
value is 97  
in equals  
1st abc     
2nd abc

Вопрос 1: почему функция equals() вызывается только один раз для проверки obj3 и obj4? Почему его не проверяют на предмет остальной части объектов?

Вопрос 2. Если ответ состоит в том, что оба они имеют один и тот же хеш-код, то будет вызываться только тогда равно, тогда почему его не вызывают для кода ниже

sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj4);

:

in hash code  
value is 98  
in hash code   
value is 97   
in hash code   
value is 99   
in hash code  
value is 97 

Он не идет внутрь метода equals(), даже если к хэш-набору добавляются два одинаковых объекта, которые имеют одинаковый хэш-код.

Вопрос 3: я повторил вышеуказанное значение и распечатал содержимое, но не были вызваны ни хэш-код, ни равно. когда его действительно полезно переопределить метод hashcode и equals?

Вопрос 4: Когда вызывается hashCode() и equals()?

4b9b3361

Ответ 1

  • Нет необходимости вызывать equals, если hashCode отличается
  • Нет необходимости вызывать hashCode, если (obj1 == obj2)
  • Нет необходимости в hashCode и/или равно для итерации - вы не сравниваете объекты
  • При необходимости различать объекты.

Ответ 2

Думаю, на ваши вопросы будет дан ответ, если вы поймете, как работают Set, и в частности HashSets. Набор представляет собой набор уникальных объектов, причем Java определяет уникальность в том, что он не равен ничему другому (равно возвращает false).

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

Ответ 3

в соответствии с исходным кодом jdk с javasourcecode.org, HashSet использует HashMap как свою внутреннюю реализацию, код о методе put из HashSet ниже:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

Правило сначала проверяет хэш, затем проверяет ссылку, а затем вызывается метод равенства объекта.

Ответ 5

Потому что во втором случае вы добавляете одну и ту же ссылку дважды, а HashSet проверяете это в HashMap.put(), на которой основана HashSet:

        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }

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

Ответ 6

Откажитесь от HashSet со всеми его методами, и вы увидите, как это работает.