Java-карта с возможными интризированными типами?

#java #hashmap

#java #hashmap

Вопрос:

Как это возможно: HashMap<byte[], byte[]> и что такое hash() байта[] ?

Комментарии:

1. Что в этом такого странного? Массивы являются объектами, поэтому это разрешено.

2. System.out.println(new byte[10].hashCode()); дает мне 209777867 .

Ответ №1:

Да, это возможно (с большой оговоркой, см. Ниже), но byte[] не является «внутренним типом». Во-первых, такого понятия не существует, вы, вероятно, имеете в виду «примитивный тип». Во-вторых: byte[] это не примитивный тип, byte есть. Массив всегда является ссылочным типом.

Массивы не имеют конкретных hashCode реализаций, поэтому они будут просто использовать hashCode of Object , что означает, что hashCode будет indentity- hashCode , который не зависит от фактического содержимого.

Другими словами: a byte[] — очень плохой Map ключ, потому что вы можете получить значение только с точно таким же экземпляром.

Если вам нужен контент hashCode() на основе массива, вы можете использовать Arrays.hashCode() , но это не поможет вам (напрямую) с Map . Также Arrays.equals() необходимо проверить равенство содержимого.

Вы могли бы обернуть свой byte[] объект в тонкую оболочку, которая реализует hashCode() и equals() (используя методы, упомянутые выше):

 import java.util.Arrays;

public final class ArrayWrapper {
  private final byte[] data;
  private final int hash;

  public ArrayWrapper(final byte[] data) {
    // strictly speaking we should make a defensive copy here,
    // but I *assume* (and should document) that the argument
    // passed in here should not be changed
    this.data = data;
    this.hash = Arrays.hashCode(data);
  }

  @Override
  public int hashCode() {
    return hash
  }

  @Override
  public boolean equals(Object o) {
    if (!(o instanceof ArrayWrapper)) {
      return false;
    }
    ArrayWrapper other = (ArrayWrapper) o;
    return this.hash == other.hash amp;amp; Arrays.equals(this.data, other.data);
  }
  // don't add getData to prevent having to do a defensive copy of data
}
  

Используя этот класс, вы можете затем использовать a Map<ArrayWrapper,byte[]> .

Комментарии:

1. Массив, вероятно, можно использовать с TreeMap, если вы реализуете свой пользовательский компаратор.

2.@AlexR: это могло бы сработать, но обратите внимание, что такой TreeMap интерфейс не будет корректно реализовывать Map интерфейс, поскольку для этого требуется Comparator , чтобы он соответствовал equals() (т. Е. compare(a,b) возвращал возврат 0 iff a.equals(b) ).

Ответ №2:

Для массивов hashCode() используется реализация по умолчанию из Object — обычно некоторая форма адреса внутреннего объекта. В результате ключ в этом HashMap считается уникальным, если это другой массив, а не если содержимое массива равно.

 byte[] a = { 2, 3 };
byte[] b = { 2, 3 };
System.out.println(a.equals(b)); // false
Map<byte[], String> map = new HashMap<byte[], String>();
map.put(a, "A");
map.put(b, "B");
System.out.println(map); // {[B@37d2068d=B, [B@7ecec0c5=A}