2017-01-31 17 views
0

Основная информация: У меня есть MyCustomObjectGenerator, который генерирует MyCustomObject. Этот объект (должен быть) всегда создается с одинаковыми значениями. Этот объект содержит mutch-код, интерфейсы, перечисления, подклассы ..., поэтому я прост в этом. Все объекты или реализации интерфейсов переопределяют равные & метод hashCode (надеюсь, правильно).Java hashCode() отличается в разных исполнениях того же самого объекта

Этот MyCustomObject сериализуется в JSON с помощью Jackson с пользовательскими сериализаторами (MyCustomObject не содержит никаких зависимостей Джексона, таких как аннотации Джексона!).

Каждый JSON получает идентификатор, рассчитанный на основе hashCode MyCustomObject (см. Код ниже). Этот идентификатор используется только как контрольная сумма, чтобы идентифицировать одни и те же jsons очень быстро. Существует еще один идентификатор, основанный на UUID, который идентифицирует задание, поэтому я знаю, что 2 задания могут иметь одну и ту же контрольную сумму!

Проблема: Есть два JUnit-тесты (минимальный & максимальный метод в одном JUnit-TestClass), которые генерируют JSON и проверить этот JSON с предопределенным JSON из файла. Если я запускаю оба теста/методы, JSON соответствует одному из файла, но если я просто запускаю метод testMaximal(), то утверждение не выполняется из-за того, что сгенерированный идентификатор не совпадает. Таким образом, hashCode, похоже, отличается. Если я снова запустил два тестовых метода, jsons снова совпадают с одним из файла, поэтому сгенерированный объект не содержит случайного содержимого, такого как ZonedDateTime.now(). Другие значения JSON всегда одинаковы, только идентификатор отличается. HashCode кажется одинаковым, если условие выполнения (2 метода/1 метод) одно и то же, но отличается, если это условие выполнения изменено. Это действительно странно для меня.

Теперь мне нужно оценить, какой класс неправильно переопределяет (или создает другой hashCode) метод hashCode (id основан на хэш-кодах всех содержащихся объектов). У кого-то есть хорошая идея распечатать хэш-код каждого объекта, переменной, подкласса, интерфейса ... из MyCustomObject через Reflection? Я уже пытался

ReflectionToStringBuilder.toString(myCustomObject, ToStringStyle.DEFAULT_STYLE) 

, но это не печатает хэш-код каждого суб-суб-элемент myCustomObject.

Если бы я мог напечатать точные значения объектов, в т.ч. hashValue, тогда я мог бы сравнить его.

Я уже нашел один объект, который отличается от ReflectionToStringBuilder.toString(), но сам этот объект содержит mutch интерфейс, переменные и т. Д., Но все значения в этом BlablaObject @ 4fb64261 [...] одинаковы, и там хэш-код отсутствует

на верхней вопрос: существуют известные случаи, что хэш-код() ведет себя странно, как «Если вы используете перечисление в качестве ключа в HashMap, то хэш-код зависит от стека Java или JVM версии» или СТГ , как это.


КОД

MyCustomObjectGenerator .java

public class MyCustomObjectGenerator { 

    private MyCustomObject(){}; 

    public static MyCustomObject generate(boolean isMinimal){ 
     //if minimal then create minimal object 
     //if minimal == false then create maximized object**strong text** 
     MyCustomObject myCustomObject = new MyCustomObject(...); 
     myCustomObject.setXY(...) 
     ... 
     return myCustomObject; 
    } 
} 

MyCustomObject.Java

import javax.xml.bind.DatatypeConverter; 
import java.io.UnsupportedEncodingException; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 
import org.apache.commons.lang3.builder.HashCodeBuilder; 
import org.apache.commons.lang3.builder.EqualsBuilder; 

public class MyCustomObject { 
    //variables, enums, interface ... here 
    ...  
    public MyCustomObject(...){...} 

    //mutch code here 
    ... 

    public String getChecksum() { 
     String id = Integer.toString(hashCode()); 
     try { 
      MessageDigest md = MessageDigest.getInstance("MD5"); 
      byte[] digest = md.digest(id.getBytes("UTF-8")); 
      id = DatatypeConverter.printHexBinary(digest); 
     } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { 
      // do nothing here 
     } 
     return new id; 
    } 

    @Override 
    public int hashCode() { 
     return new HashCodeBuilder(-1013166723, 372138085) 
     //if needed in extended classes: .appendSuper(super.hashCode()) 
     .append(...) 
     .... 
     .toHashCode(); 
    } 

    @Override 
    public boolean equals(
      final Object other) { 
     if (!(other instanceof MyCustomObject)) { 
      return false; 
     } 
     MyCustomObject castOther = (MyCustomObject) other; 
     return new EqualsBuilder() 
      // if needed in extended classes: .appendSuper(super.hashCode()) 
      .append(..., ...) 
      .... 
      .isEquals(); 
    } 
} 
+1

Значение по умолчанию hashCode() определяется как super.hashCode() (реализация java.lang.Object), поэтому для каждого экземпляра JVM он отличается. Контракты HashCode заключают в себе: «Это целое число не должно оставаться согласованным с одним исполнением приложения на другое выполнение одного и того же приложения». Поэтому я предполагаю, что у вас это есть: либо вы переопределяете каждый метод hashCode(), даже для перечислений, чтобы обеспечить их стабильность по сравнению с экземплярами JVM, или ваши хэши будут различаться для каждого экземпляра. – GPI

ответ

2

Существует множество типов, в которых значение, возвращаемое hashCode(), будет варьироваться от одного приложения к другому. Это включает в себя:

  • Все типы массивов
  • Все enum типы
  • Многие другие типы объектов, где равенство и идентичность объекта одно и то же; например Object, Класс , Нить , StringBuilder / StringBuffer`.

По общему правилу, если класс определен как с помощью Java SE не документально как имеющие equals метод, который отличается в семантике от Object.equals(Object), то следует считать, что он также использует Object.hashCode() ... и что хэш-коды будут отличаться от одного прогона к другому.

1

Вы не должны использовать hashCode() для ковша выбирают в структуре данных, хэш на основе исключением. Как вы узнали, это не имеет никакого смысла в проверке.

 Смежные вопросы

  • Нет связанных вопросов^_^