HashMap на Java


Сегодня у меня было интервью, и я получил следующий код Java:

public class Question_6 {
    public static void main(String[] args){
        Map<Integer,String> map1 = new HashMap<Integer,String>();
        map1.put(new Integer(1),"001a");
        map1.put(new Integer(1),"001b");
        map1.put(new Integer(2),"002");

        System.out.println(map1.size());

        Map<MyInt,String> map2 = new HashMap<MyInt,String>();
        map2.put(new MyInt(1),"001a");
        map2.put(new MyInt(1),"001b");
        map2.put(new MyInt(2),"002");

        System.out.println(map2.size());

    }

}
public class MyInt {
    int i;
    public MyInt(int i) {
       this.i = i;
    }

}

Вопросы были следующие:

  1. Что будет напечатано на консоли?

  2. Предложите решение проблемы.

Теперь я знаю, что ответ на первый вопрос таков:

2

3

Но я не знаю, почему? В чем проблема с MyInt?

5   2  

5 ответов:

Ваша проблема заключается в том, что equals() и hashcode() не реализованы на MyInt.

В обоих случаях ожидается, что в результате вы получите 2.

HashMap, как следует из названия, группирует ключи в корзины на основе хэш-кода ключей () . Но хэш-код по умолчанию не совпадает для двух экземпляров MyInt с одинаковым значением.

Чтобы определить равенство, вы также должны переопределить equals().

Одно решение:

public class MyInt {

    [...]

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

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

}

Вам нужно переопределить метод equals() и hashCode() в вашем классе MyInt, Чтобы HashMap мог понять new MyInt(1).equals(new MyInt(1)) является true.

Класс Integer переопределяет метод equals() Для сравнения значений. Хэш-карты не могут содержать два ключа, которые "равны", поэтому 2-я вставка в map1 перезапишет первую запись. Кроме того, метод hashcode() переопределяется.

Однако MyInt не переопределяет метод equals() или hashcode(), поэтому равенство основано на расположении памяти. Таким образом, map2 видит три различных ключа и делает три различных записи.

    Map<MyInt,String> map2 = new HashMap<MyInt,String>();
    MyInt one = new MyInt(1);
    MyInt two = new MyInt(2);
    map2.put(one,"001a");
    map2.put(one,"001b");
    map2.put(two,"002");

    System.out.println(map2.size());

Производит выход 2 в этом случае, потому что один.равенство (один) истинно в этом случае.

map1.put(new Integer(1),"001a");
        map1.put(new Integer(1),"001b");//same location in map
        map1.put(new Integer(2),"002");

В этой части вы используете целочисленный класс, целочисленный класс не позволяет устанавливать одно и то же местоположение, но ваш целочисленный класс позволяет.

Измените код вот так, и вы увидите проблему

public class Question_6 {
    public static void main(String[] args){
        Map<Integer,String> map1 = new HashMap<Integer,String>();
        map1.put(new Integer(1),"001a");
        map1.put(new Integer(2),"001b");
        map1.put(new Integer(3),"002");

        System.out.println(map1.size());

        Map<MyInt,String> map2 = new HashMap<MyInt,String>();
        map2.put(new MyInt(1),"001a");
        map2.put(new MyInt(2),"001b");
        map2.put(new MyInt(3),"002");

        System.out.println(map2.size());

    }

Этот код будет напечатан;

3 3

Итак, ваш целочисленный класс (myInt) истинен, но отсутствует

Необходимо переопределить методы hashCode() и equals. Для всех случаев, когда equals возвращает true для двух объектов, hashCode возвращает одно и то же значение. Хэш-код - это код, который должен быть равен, если два объекта равны

Но почему??

Если вы проверяете в исходном коде HashMap.метод put . вы можете видеть, что этот метод проверяет как hashcode, так и equality перед вставкой. Поэтому, если вы не переопределите эти методы, он будет использовать методы суперкласса (объекта), которые будут возвращает различные значения для различных объектов. Таким образом, хотя для одного и того же ключа два значения будут вставлены в отдельное место Hashmap. Таким образом, вам нужно переопределить эти два и убедиться, что для двух одинаковых объектов вы должны вернуть то же самое hashcode.

Код

Таким образом, ваш MyInt должен быть чем-то вроде

public class MyInt {
    int i;
    public MyInt(int i) {
       this.i = i;
    }        

    public int hashCode() {
       return i;
    }    

    public boolean equals(Object obj) {
        if (obj instanceof MyInt && i == ((MyInt)obj).i) {
            return true;
        } else
            return false;
    }
}