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;
}
}
Вопросы были следующие:
-
Что будет напечатано на консоли?
-
Предложите решение проблемы.
Теперь я знаю, что ответ на первый вопрос таков:
2
3
Но я не знаю, почему? В чем проблема с MyInt?
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; } }