Java HashMap с массивом Int
Я использую этот код, чтобы проверить, что массив присутствует в HashMap
:
public class Test {
public static void main(String[] arg) {
HashMap<int[], String> map = new HashMap<int[], String>();
map.put(new int[]{1, 2}, "sun");
System.out.println(map.containsKey((new int[]{1, 2})));
}
}
Но это печатает False
. Как я могу проверить, что массив присутствует в HashMap
?
Ответы
Ответ 1
Проблема в том, что два int[]
не равны.
System.out.println(
(new int[] { 1, 2 }).equals(new int[] { 1, 2 })
); // prints "false"
Map
и другие классы Java Collections Framework определяют его интерфейс с точки зрения equals
. Из Map API
:
Многие методы в интерфейсах Collections Framework определены в терминах метода equals
. Например, спецификация для метода containsKey(Object key)
гласит: "возвращает true
том и только в том случае, если эта карта содержит отображение для ключа k
такое, что (key==null? k==null: key.equals(k))
. "
Обратите внимание, что они не должны быть одним и тем же объектом; они просто должны быть equals
. Массивы в Java расширяются от Object
, чья реализация equals
умолчанию возвращает true только для идентификатора объекта; следовательно, почему он печатает false
в приведенном выше фрагменте.
Вы можете решить свою проблему одним из многих способов:
- Определите свой собственный класс-оболочку для массивов, для которых
equals
использует метод java.util.Arrays
equals/deepEquals
. - И не забывайте, что когда вы
@Override equals(Object)
, вы также должны @Override hashCode
- Используйте что-то вроде
List<Integer>
которое определяет equals
в терминах значений, которые они содержат - Или, если вы можете работать с равенством ссылок для
equals
, вы можете просто придерживаться того, что у вас есть. Точно так же, как вы не должны ожидать, что приведенный выше фрагмент будет выводить true
, вы не должны ожидать, что сможете найти ваши массивы только по его значениям; Вы должны держаться и использовать оригинальные ссылки каждый раз.
Смотрите также:
API
Ответ 2
Вы сравниваете две разностные ссылки - обратите внимание на двойное использование new
.
Что-то вроде этого будет работать:
public class Test {
public static void main(String[] arg)
{
HashMap<int[],String> map= new HashMap<int[],String>();
int[] a = new int[]{1,2};
map.put(a, "sun");
System.out.println(map.containsKey(a));
}
}
Так как a
является той же ссылкой, вы получите true
, как ожидалось. Если ваше приложение не имеет возможности передавать ссылки для сравнения, я бы создал новый тип объекта, который содержит int[]
и переопределяет метод equals()
(не забудьте одновременно переопределить hashCode()
), так что будет отображаться в вызове containsKey()
.
Ответ 3
Я бы использовал другой подход. Как упоминалось ранее, проблема заключается в равенстве массивов, которое основано на эталонном равенстве и делает вашу карту бесполезной для ваших нужд.
Другая потенциальная проблема, предполагающая, что вы используете ArrayList, - это проблема согласованности: если вы измените список после добавления на карту, у вас будет повреждение hashmap, поскольку позиция списка больше не будет отражать его хэш-код.
Чтобы решить эти две проблемы, я бы использовал какой-то неизменный список. Например, вы можете создать неизменяемую оболочку для массива int и реализовать equals() и hashCode() самостоятельно.
Ответ 4
Я думаю, проблема в том, что ваш массив выполняет сравнение "==", то есть проверяет ссылку. Когда вы делаете containsKey (новый int [] {...}), он создает новый объект и, следовательно, эта ссылка не является одинаковой.
Если вы измените тип массива на нечто вроде ArrayList<Integer>
, которое должно работать, однако я бы старался избегать использования списков в качестве ключей карты, поскольку это не будет очень эффективным.
Ответ 5
Реализация hashCode()
для массивов выводится из Object.hashCode()
, поэтому она зависит от расположения памяти массива. Поскольку два массива создаются отдельно, они имеют разные ячейки памяти и, следовательно, разные хэш-коды. Если вы сделали один массив, он будет работать:
int[] arr = {1, 2};
map.put(arr, "sun");
System.out.println(map.containsKey(arr));
Ответ 6
У вас есть два разных объекта, которые содержат одни и те же значения, потому что вы дважды вызывали новый код.
Один из подходов, который вы можете использовать, - создать собственный класс "владелец" и определить его равные и хэш-методы.
Ответ 7
Вы уверены, что не хотите отображать Strings
в массивы, а не наоборот?
В любом случае, чтобы ответить на ваш вопрос, проблема в том, что вы создаете массив new
при вызове containsKey()
. Это возвращает false между вами, у вас есть два отдельно new
ed массива, которые имеют одинаковые элементы и измерение. См. Ответ Yuval, чтобы увидеть правильный способ проверки, содержится ли массив в качестве ключа.
Альтернативный более продвинутый подход заключается в создании собственного класса, который обертывает массив и перезаписывает hashCode()
, так что два массива с одинаковыми размерами и элементами будут иметь одинаковые хэш-коды.