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