Подтвердить что ты не робот

Objects.hash() vs Objects.hashCode(), необходимо уточнение

в Java 7 у нас есть

o.hashCode();
Objects.hashCode(o);

    Objects.hash(o);

Первые 2 примерно одинаковы с проверкой нулевой точки, но что является последним?

Когда указана одна ссылка на объект, возвращаемое значение не равно хеш-коду этой ссылки на объект.

Это почему? Я имею в виду, что нам не нужны 3 метода, которые делают одно и то же, я это понимаю, но зачем вообще нужен Objects.hash()? Когда бы вы решили использовать один против другого?

4b9b3361

Ответ 1

Смотрите документацию для hashCode и hash. hash принимает Object... в то время как hashCode - Object hashCode принимает Object. Приведенный пример:

@Override public int hashCode() {
    return Objects.hash(x, y, z);
}
  • Objects.hash(Object... values) следует использовать в тех случаях, когда вы хотите хеш последовательности объектов, например, при определении собственного метода hashCode и хотите просто закодировать хеш для нескольких значений, которые составляют идентичность вашего объект.
  • Objects.hashCode(Object o) следует использовать, когда вы хотите хеш одного объекта, без броска, если объект нулевой.
  • Object::hashCode() следует использовать, когда вы хотите хеш одного объекта, и будет выдавать исключение, если объект имеет значение null.

Обратите внимание, что hash(o) и hashCode(o) не обязательно возвращают одно и то же! Если вы делаете это для одного объекта, вам, вероятно, следует использовать hashCode.

Ответ 2

По умолчанию hashCode() объекта возвращает адрес памяти для объекта. Так что, если у вас есть следующий класс:

class Car {
    String make;
    String model;
    int year;

    public Car(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }
} 

затем создайте два объекта:

Car car1 = new Car("Toyota", "Corolla", 2010);
Car car2 = new Car("Toyota", "Corolla", 2010);

car1.hashCode() будет отличаться от car2.hashCode(), потому что у каждого объекта будет свой адрес памяти.

Что если вы хотите, чтобы car1 и car2 возвращали один и тот же хэш-код? В этом случае вы должны переопределить метод hashCode() объекта по умолчанию для класса Car следующим образом:

@Override
public int hashCode() {
    Object[] x = {model, make, Integer.valueOf(year)};
    int hashArray = Arrays.hashCode(x);
    return hashArray;
}

Это сделает car1.hashCode() равным car2.hashCode(), потому что String.hashCode() вычисляет hashCode на основе содержимого строки, а Integer.hashCode() возвращает само целочисленное значение.

В Java 7 вы можете просто использовать Objects.hash(Object... values). Итак, наш новый Car hashCode() будет выглядеть следующим образом:

@Override
public int hashCode() {
    return Objects.hash(model, make, year);
}

Objects.hash(Object... values) вызовет Arrays.hashCode для вас.

Наконец, Objects.hashCode(Object o) выполнит нулевую проверку. Он вернет 0, если объект нулевой. Иначе, он вызовет метод hashCode() объектов.

Ответ 3

Objects.hashCode

Objects.hashCode( Object o ) метод Objects.hashCode( Object o ) просто вызывает метод hashCode для переданного объекта.

Терпит NULL

Так зачем изобретать или использовать этот метод? Почему бы просто не вызвать метод hashCode объектов самостоятельно?

Этот метод предлагает одно преимущество: NULL0. Служебный метод допускает нулевое значение.

  • Если вы вызываете Objects.hashCode( myObject ) где myObject равен NULL, вы получаете ноль (0).
  • Напротив, вызов myObject.hashCode() когда myObject равен NULL вызывает аргумент NullPointerException.

Желательно ли терпеть ноль или нет, зависит от вашего собственного суждения в вашей конкретной ситуации.

Objects.hash

Objects.hash( Object o, … ) метод Objects.hash( Object o, … ) служит для другой цели. Этот метод имеет две фазы:

  • Вызовите .hashCode для каждого переданного объекта, собирая каждый результат.
  • Рассчитайте хеш по собранным результатам.

хеш хеш

Если вы передаете один объект Objects.hash( myObject ), сначала вызывается и собирается myObject.hashCode, а затем вычисляется хэш для этой коллекции из одного элемента. Итак, вы получите хеш хеша.

При хешировании одного объекта важно понимать, что Objects.hashCode( myObject ) возвращает результат, отличный от Objects.hash( myObject ). По сути, второе возвращает хеш по результату первого.

Раздражает на практике

Логика подхода, принятого в этих двух методах Objects, сама по себе имеет смысл.

К сожалению, на практике для тех из нас, кто пытается использовать их в повседневной работе при написании кода на наших объектах POJO для переопределения hashCode и, соответственно, equals, мы должны дважды подумать, чтобы решить, какой из них вызывать.

  • Если ваше переопределение hashCodeequals) основано на одном члене вашего класса, используйте Objects.hashCode( member ).
  • Если ваше переопределение hashCodeequals) основано на нескольких атрибутах вашего класса, используйте Objects.hash( memberA, memberB, memberC ).

Единственный член, не терпящий NULL

@Override
public int hashCode() {
    return this.member.hashCode() ;  // Throws NullPointerException if member variable is null.
}

Единственный член, допускающий значение NULL

@Override
public int hashCode() {
    return Objects.hashCode( this.member ) ;  // Returns zero (0) if 'this.member' is NULL, rather than throwing exception.
}

Multi-член, терпящий NULL

@Override
public int hashCode() {
    return Objects.hash( this.memberA , this.memberB , this.memberC  ) ;  // Hashes the result of all the passed objects individual hash codes.  
}

пример

Мы можем протестировать эти различные методы довольно просто.

UUID

Давайте использовать объект UUID в качестве примера. UUID (универсальный уникальный идентификатор) - это 128-битное значение, в котором определенные биты имеют определенную семантику.

Реализация UUID OpenJDK внутренне представляет 128-битное значение в виде пары 64-битных long целых чисел.

Та же самая реализация переопределяет Object::equals и Object::hashCode для просмотра данных, хранящихся в этой паре длинных целых чисел. Вот исходный код для этих двух методов.

public boolean equals(Object obj) {
    if ((null == obj) || (obj.getClass() != UUID.class))
        return false;
    UUID id = (UUID)obj;
    return (mostSigBits == id.mostSigBits &&
            leastSigBits == id.leastSigBits);
}
public int hashCode() {
    long hilo = mostSigBits ^ leastSigBits;
    return ((int)(hilo >> 32)) ^ (int) hilo;
}

Пример кода

Создайте объект UUID.

UUID uuid = UUID.randomUUID();

Рассчитайте наши значения хеша.

int hash1 = uuid.hashCode();
int hash2 = Objects.hashCode( uuid );  // Result matches line above.

int hash3 = Objects.hash( uuid );  // Returns a hash of a hash.
int hash4 = Objects.hash( uuid.hashCode() ); // Result matches line above.

Дамп на консоль.

System.out.println( "uuid.toString(): " + uuid.toString() );
System.out.println( " 1/2 = " + hash1 + " | " + hash2 );
System.out.println( " 3/4 = " + hash3 + " | " + hash4 );

Смотрите этот код в прямом эфире на IdeOne.com.

uuid.toString(): 401d88ff-c75d-4607-bb89-1f7a2c6963e1

1/2 = 278966883 | 278966883

3/4 = 278966914 | 278966914