[java] 컬렉션의 hashCode 메서드에 대한 최상의 구현

hashCode()컬렉션에 가장 적합한 메서드 구현을 결정하려면 어떻게해야합니까 (메소드와 같은 것이 올바르게 재정의되었다고 가정)?



답변

최고의 구현? 사용법 패턴에 따라 다르므로 어려운 질문입니다.

거의 모든 경우에 합리적인 구현이 Josh Bloch효과적인 Java 항목 8 (제 2 판)에서 제안되었습니다 . 가장 좋은 방법은 저자가 접근 방식이 좋은 이유를 설명하기 때문에 거기서 찾아 보는 것입니다.

짧은 버전

  1. a를 작성하고 0이 아닌 값을 int result지정 하십시오 .

  2. 들어 모든 분야 f 에서 테스트 equals()방법의 해시 코드를 계산 c하여 :

    • 필드 f가 a 인 경우 boolean: 계산 (f ? 0 : 1);
    • 필드 F 인 경우 byte, char, short또는 int: 계산 (int)f;
    • 필드 f가 a 인 경우 long: 계산 (int)(f ^ (f >>> 32));
    • 필드 f가 a 인 경우 float: 계산 Float.floatToIntBits(f);
    • 필드 f가 a 인 경우 double: Double.doubleToLongBits(f)모든 긴 값처럼 리턴 값을 계산 하고 처리하십시오.
    • 필드 f가 객체 인 경우 : hashCode()메소드 의 결과를 사용 하거나 0이면 f == null;
    • 필드 f가 배열 인 경우 : 모든 필드를 별도의 요소로보고 해시 값을 재귀적인 방식으로 계산하고 다음에 설명 된대로 값을 결합하십시오.
  3. 해시 값 cresult다음 과 결합하십시오 .

    result = 37 * result + c
  4. 반환 result

이로 인해 대부분의 사용 상황에 적절한 해시 값이 배포됩니다.


답변

dmeister가 권장하는 효과적인 Java 구현에 만족하면 직접 롤링하는 대신 라이브러리 호출을 사용할 수 있습니다.

@Override
public int hashCode() {
    return Objects.hashCode(this.firstName, this.lastName);
}

여기에는 Guava ( com.google.common.base.Objects.hashCode) 또는 Java 7 ( java.util.Objects.hash) 의 표준 라이브러리가 필요 하지만 같은 방식으로 작동합니다.


답변

꽤 좋은 일을하는 Eclipse가 제공하는 기능을 사용하는 것이 좋으며 비즈니스 로직을 개발하는 데 노력과 에너지를 투입 할 수 있습니다.


답변

이것은 Android문서 (Wayback Machine)Github의 내 코드 와 연결되어 있지만 일반적으로 Java에서 작동합니다. 내 대답은 읽고 이해하기 훨씬 쉬운 코드 로 dmeister의 답변 을 확장 한 것입니다.

@Override
public int hashCode() {

    // Start with a non-zero constant. Prime is preferred
    int result = 17;

    // Include a hash for each field.

    // Primatives

    result = 31 * result + (booleanField ? 1 : 0);                   // 1 bit   » 32-bit

    result = 31 * result + byteField;                                // 8 bits  » 32-bit 
    result = 31 * result + charField;                                // 16 bits » 32-bit
    result = 31 * result + shortField;                               // 16 bits » 32-bit
    result = 31 * result + intField;                                 // 32 bits » 32-bit

    result = 31 * result + (int)(longField ^ (longField >>> 32));    // 64 bits » 32-bit

    result = 31 * result + Float.floatToIntBits(floatField);         // 32 bits » 32-bit

    long doubleFieldBits = Double.doubleToLongBits(doubleField);     // 64 bits (double) » 64-bit (long) » 32-bit (int)
    result = 31 * result + (int)(doubleFieldBits ^ (doubleFieldBits >>> 32));

    // Objects

    result = 31 * result + Arrays.hashCode(arrayField);              // var bits » 32-bit

    result = 31 * result + referenceField.hashCode();                // var bits » 32-bit (non-nullable)   
    result = 31 * result +                                           // var bits » 32-bit (nullable)   
        (nullableReferenceField == null
            ? 0
            : nullableReferenceField.hashCode());

    return result;

}

편집하다

일반적으로을 무시하면을 (를) 재정의 hashcode(...)하려고합니다 equals(...). 따라서 이미 구현했거나 이미 구현 한 사람들을 위해 equals여기 Github에서 좋은 참조가 있습니다

@Override
public boolean equals(Object o) {

    // Optimization (not required).
    if (this == o) {
        return true;
    }

    // Return false if the other object has the wrong type, interface, or is null.
    if (!(o instanceof MyType)) {
        return false;
    }

    MyType lhs = (MyType) o; // lhs means "left hand side"

            // Primitive fields
    return     booleanField == lhs.booleanField
            && byteField    == lhs.byteField
            && charField    == lhs.charField
            && shortField   == lhs.shortField
            && intField     == lhs.intField
            && longField    == lhs.longField
            && floatField   == lhs.floatField
            && doubleField  == lhs.doubleField

            // Arrays

            && Arrays.equals(arrayField, lhs.arrayField)

            // Objects

            && referenceField.equals(lhs.referenceField)
            && (nullableReferenceField == null
                        ? lhs.nullableReferenceField == null
                        : nullableReferenceField.equals(lhs.nullableReferenceField));
}


답변

먼저 equals가 올바르게 구현되었는지 확인하십시오. 에서 IBM의 developerWorks 기사 :

  • 대칭 : 두 참조 a와 b의 경우 b.equals (a) 인 경우에만 a.equals (b)
  • 반사성 : null이 아닌 모든 참조의 경우 a.equals (a)
  • 전이성 : aequals (b) 및 b.equals (c)이면 a.equals (c)

그런 다음 hashCode와의 관계가 동일한 기사의 연락처를 존중하는지 확인하십시오.

  • hashCode ()와의 일관성 : 두 개의 동일한 객체는 동일한 hashCode () 값을 가져야합니다.

마지막으로 좋은 해시 함수는 이상적인 해시 함수 에 접근하기 위해 노력해야 합니다 .


답변

about8.blogspot.com, 당신은 말했다

두 객체에 대해 equals ()가 true를 반환하면 hashCode ()는 동일한 값을 반환해야합니다. equals ()가 false를 반환하면 hashCode ()는 다른 값을 반환해야합니다

나는 당신에 동의 할 수 없습니다. 두 객체에 동일한 해시 코드가있는 경우 동일한 해시 코드를 의미 할 필요는 없습니다.

A가 B와 같으면 A.hashcode는 B.hascode와 같아야합니다.

그러나

A.hashcode가 B.hascode와 같다고해서 A가 B와 같아야한다는 의미는 아닙니다.


답변

이클립스를 사용하면 다음을 생성 equals()하고 hashCode()사용할 수 있습니다 .

소스-> hashCode () 및 equals () 생성

이 함수 를 사용하면 동등성 및 해시 코드 계산에 사용할 필드 를 결정할 수 있으며 Eclipse는 해당 메소드를 생성합니다.