Объекты равняются (), хэш-код () и toString (). Как правильно реализовать их?

Я реализую equals(), hashCode() и toString() из моих объектов с помощью всех доступных полей в бобе.

Я получаю некоторое Ленивое init Исключение на frontend, когда я пытаюсь сравнить равенство или когда я печатаю состояние obj. Поэтому некоторый список в объекте может быть ленив инициализированный.

Я задаюсь вопросом, к чему корректный путь для реализации equals() и toString() на объекте объекта.

32
задан Bozho 19 November 2010 в 00:06
поделиться

6 ответов

Помимо того, что сказали другие, я также думаю, что объект Hibernate должен быть подключен к сеансу, чтобы получить ленивый Информация. Без подключения к базе данных эти списки не могут быть загружены :)

0
ответ дан 27 November 2019 в 21:09
поделиться

Когда вы реализуете методы equals и hashCode для объектов Hibernate, важно

  1. Использовать геттеры вместо прямого доступа к свойствам класса.
  2. Не сравнивать напрямую классы объектов, а использовать instanceof вместо этого

Дополнительная информация:

Stackoverflow: overriding-equals-and-hashcode-in-java

Документация Hibernate: Equals и HashCode

Редактировать: те же правила о недопустимости прямого доступа к свойствам класса применимы и к методу toString - только использование геттеров гарантирует, что будет возвращена информация, действительно содержащаяся в классе.

10
ответ дан 27 November 2019 в 21:09
поделиться
  1. Если два объекта равны, они должны иметь одинаковый хэш-код.
  2. Метод equals () по умолчанию проверяет, ссылаются ли две ссылки на один и тот же экземпляр в памяти в куче Java

Вы можете полагаться на идентификатор объекта , чтобы сравнить свой объект с помощью equals

public boolean equals(Object o) {
    if(o == null)
        return false;

   Account account = (Account) o;
   if(!(getId().equals(account.getId())))
       return false;

   return true;
}

Но что происходит, когда у вас есть непостоянная сущность. Он не будет работать , потому что его идентификатор не был назначен.

Итак, давайте посмотрим, что говорит об этом Java Persistence with Hibernate Book

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

Итак

Это естественный ключ, который вы бы использовали , если бы вместо этого вы не использовали суррогатный первичный ключ.

Итак, предположим, что у вас есть пользовательский объект, и его естественными ключами являются firstName и lastName (по крайней мере, его / ее firstName и lastName часто не меняются). Так что он будет реализован как

public boolean equals(Object o) {
    if(o == null)
        return false;

    if(!(o instanceof User))
        return false;

    // Our natural key has not been filled
    // So we must return false;
    if(getFirstName() == null && getLastName() == null)
        return false;

    User user = (User) o;
    if(!(getFirstName().equals(user.getFirstName())))
        return false;

    if(!(getLastName().equals(user.getLastName())))
        return false;

   return true;
}

// default implementation provided by NetBeans
public int hashcode() {
    int hash = 3;

    hash = 47 * hash + ((getFirstName() != null) ? getFirstName().hashcode() : 0)
    hash = 47 * hash + ((getLastName() != null) ? getLastName().hashcode() : 0)

    retrun hash;
}

Он отлично работает! Я использую даже с Mock-объектами, такими как репозитории, службы и т. Д.

А насчет метода toString (), как сказал @Bozho, вы можете помещать любую интересную информацию. Но помните, что некоторые веб-фреймворки, такие как Wicket и Vaadin, например, используют этот метод для отображения его значений.

7
ответ дан 27 November 2019 в 21:09
поделиться

equals () и hashCode () должны быть реализованы с использованием бизнес-ключа - то есть набора свойств, которые однозначно идентифицируют объект, но не являются его автоматическими сгенерированный ID.

в toString () вы можете поместить любую интересующую информацию - например, все поля.

Используйте вашу IDE (Eclipse, NetBeans, IntelliJ), чтобы сгенерировать все это для вас.

Чтобы избежать LazyInitializationException , независимо от того, в equals () или в вашем представлении (jsp), вы можете использовать OpenSessionInView .

17
ответ дан 27 November 2019 в 21:09
поделиться

Моя реализация toString() für Hibernate entities выглядит следующим образом:

@Override
public String toString() {
    return String.format("%s(id=%d)", this.getClass().getSimpleName(), this.getId());
}

Каждый подкласс моего AbstractEntity (выше) переопределяет этот метод при необходимости:

@Override
public String toString() {
    return String.format("%s(id=%d, name='%s', status=%s)",
            this.getClass().getSimpleName(),
            this.getId(),
            this.getName(),
            this.getStatus());
}

Для hashCode() и equals() имейте в виду, что Hibernate часто использует прокси-классы. Поэтому мой equals() обычно выглядит так:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;

    Class<AbstractEntity> c1 = Hibernate.getClass(this);
    Class<AbstractEntity> c2 = Hibernate.getClass(obj);
    if (!c1.equals(c2)) return false;

    final AbstractEntity other = (AbstractEntity) obj;
    if (this.getId() == null) {
        if (other.getId() != null) return false;
    }
    else if (!this.getId().equals(other.getId())) return false;

    return true;
}

И, как уже было сказано другими... будьте осторожны с доступом к лениво загруженным свойствам! Простой toString() или даже log.debug(entity) может вызвать огромную активность при каскадировании на несколько лениво загруженных объектов и свойств.

0
ответ дан 27 November 2019 в 21:09
поделиться

Мы реализуем equals () и hashCode () в нашем суперклассе. Это работает безупречно, особенно в картах, списках и т. Д. Это должно было быть правильным, поскольку мы делаем много переходной настойчивости.

equals ():

/**
 * Compare two entity objects, following hibernate semantics for equality. Here we assume that
 * new objects are always different unless they are the same object. If an object is loaded from
 * the database it has a valid id and therefore we can check against object ids.
 *
 * @see com.dolby.persist.bean.EntityObject#equals(java.lang.Object)
 */
@SuppressWarnings("unchecked")
@Override
public final boolean equals(final Object object) {
    if (this == object) return true;
    if (object == null || this.getClass() != object.getClass()) return false;
    final AbstractModelObject<ID> other = (AbstractModelObject<ID>) object;
    if (this.getId() == null || other.getId() == null) return false;
    return this.getId().equals(other.getId());
}

hashCode ():

/**
 * Returns an enttiy objects hashcode.
 * <p>
 * What we are doing here is ensuring that once a hashcode value is used, it never changes for
 * this object. This allows us to use object identity for new objects and not run into the
 * problems.
 * </p>
 * <p>
 * In fact the only case where this is a problem is when we save a new object, keep it around
 * after we close the session, load a new instance of the object in a new session and then
 * compare them.
 * </p>
 * <p>
 * in this case we get A==B but a.hashcode != b.hashcode
 * </p>
 * <p>
 * This will work in all other scenarios and don't lead to broken implementations when the
 * propety of the object are edited. The whole point in generating synthetic primary keys in the
 * first place is to avoid having a primary key which is dependant on an object property and
 * which therefore may change during the life time of the object.
 * </p>
 *
 * @see java.lang.Object#hashCode()
 */
@Override
public final synchronized int hashCode() {
    if (this.hashcodeValue == null) {
        if (this.getId() == null) {
            this.hashcodeValue = new Integer(super.hashCode());
        }
        else {
            final int generateHashCode = this.generateHashCode(this.getId());
            this.hashcodeValue = new Integer(generateHashCode);
        }
    }
    return this.hashcodeValue.intValue();
}
0
ответ дан 27 November 2019 в 21:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: