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

Как создать контрольную сумму для Java-объекта

Я ищу решение для создания контрольной суммы для любого типа объекта Java, которое остается неизменным для каждого выполнения приложения, которое создает тот же объект.

Я попробовал это с Object.hashCode(), но api говорит

.... Это целое число не должно оставаться согласованным с одним исполнением приложения на другое выполнение того же приложения.

4b9b3361

Ответ 1

У меня была схожая проблема (создание хорошего хэш-кода для файлов XML), и я узнал, что лучшим решением является использование MD5 через MessageDigest или если вам нужно что-то быстрее: Fast MD5. Обратите внимание, что даже если Object.hashCode будет одинаковым, каждый раз он слишком короткий (всего 32 бита), чтобы обеспечить высокую уникальность. Я думаю, что 64 бита - это минимум, чтобы вычислить хороший хэш-код. Имейте в виду, что MD5 генерирует хэш-код длиной 128 бит, что в этой ситуации еще больше необходимо.

Конечно, для использования MessageDigest вам необходимо сначала сериализовать (в вашем случае маршалл) объект.

Ответ 2

Пример

private BigInteger checksum(Object obj) throws IOException, NoSuchAlgorithmException {

    if (obj == null) {
      return BigInteger.ZERO;   
    }

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(obj);
    oos.close();

    MessageDigest m = MessageDigest.getInstance("SHA1");
    m.update(baos.toByteArray());

    return new BigInteger(1, m.digest());
}

Ответ 3

public static String getChecksum(Serializable object) throws IOException, NoSuchAlgorithmException {
    ByteArrayOutputStream baos = null;
    ObjectOutputStream oos = null;
    try {
        baos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] thedigest = md.digest(baos.toByteArray());
        return DatatypeConverter.printHexBinary(thedigest);
    } finally {
        oos.close();
        baos.close();
    }
}

Ответ 4

Думаю, вам стоит взглянуть на serialization. Механизм сериализации должен решить аналогичную проблему, поэтому вы можете посмотреть, как она реализована.

Но если вы описываете проблему, которую пытаетесь решить, вы, вероятно, получите более точное решение.

Ответ 5

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

Ответ 6

Хотите ли вы сделать это для всех объектов Java?

В этом случае hashCode() не работает.

Для некоторых классов hashCode() существует более строгое определение, гарантирующее равенство во всех исполнениях. Например String имеет четко определенную реализацию hashCode. Аналогично List и Set хорошо -определенные значения, если все содержащиеся в них объекты также имеют четко определенные значения (обратите внимание, что общий Collection.hashCode() не требует значения для быть четко определенными).

Для других классов вам придется использовать отражение рекурсивно с некоторой четко определенной формулой для построения контрольной суммы.

Ответ 7

Хаскод в порядке. Либо данный класс переопределяет equals, а также, как требует контракт, hashcode. По контракту, если equals возвращает true, hashcode должен быть тем же.
Или класс не переопределяет equals. В этом случае разные исполнения вашего приложения не могут создать один и тот же объект, поэтому проблем нет.
Единственная проблема заключается в том, что некоторые классы (даже из Java API) нарушают контракт для equals.

Ответ 8

Библиотека Apache commons lang предоставляет класс HashCodeBuilder, который помогает создавать хэш-код, который заполняет ваши требования из свойств класса.

Пример:

   public int checksum() {
     // you pick a hard-coded, randomly chosen, non-zero, odd number
     // ideally different for each class
     return new HashCodeBuilder(17, 37).
       append(property1).
       append(property2).
       append(property3).
       toHashCode();
   }

См. Commons Lang API

Ответ 9

Если вы используете Eclipse IDE, тогда у него есть действия (в меню "Источник" ) для генерации символов hashcode и equals. Он позволяет вам выбирать атрибуты класса, который вы хотите в хэш-коде. Это похоже на использование ранее предложенного подхода HashCodeBuilder.

В качестве альтернативы вы можете передать объект в массив байтов и создать MD5 из этого.

Ответ 10

  • Объект → Строка (например, GSON - вам не придется писать сериализацию, чтобы не перечислить все поля вашего класса)

  • String.hashCode() → int (вместо Object.hashCode()! Эта реализация hashCode() зависит от содержимого String, а не от адреса в памяти --- вы можете использовать его в другом приложении запуски, различные потоки и т.д.)

(или 2. String → md5)