[java] Java 문자열에서 hashCode ()의 일관성

Java String의 hashCode 값은 ( String.hashCode () ) 로 계산됩니다 .

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

다음 표현식이 거짓으로 평가되는 환경 (JVM 버전, 공급 업체 등)이 있습니까?

boolean expression = "This is a Java string".hashCode() == 586653468

업데이트 # 1 : 답변이 “예, 그러한 환경이 있습니다”라고 주장하는 경우 “이것은 Java 문자열”입니다. 구체적인 예를 제공하십시오. hashCode ()! = 586653468 가능한 한.

업데이트 # 2 : 우리는 hashCode ()의 구현 세부 사항에 의존하는 것이 일반적으로 나쁘다는 것을 알고 있습니다. 그러나 String.hashCode ()에 대해 구체적으로 이야기하고 있으므로 String.hashCode ()에 집중하십시오. Object.hashCode ()는이 질문과 관련이 없습니다.



답변

Java 1.2까지 그 문서를 볼 수 있습니다.

일반적으로 동일하게 유지되는 해시 코드 구현에 의존해서는 안된다는 것은 사실이지만 이제는에 대한 동작이 문서화 java.lang.String되었으므로 변경하면 기존 계약을 위반하는 것으로 계산됩니다.

가능한 경우, 버전 등에서 동일하게 유지되는 해시 코드에 의존해서는 안됩니다.하지만 java.lang.String알고리즘 지정되어 있기 때문에 단순히 마음 에 특별한 경우 가 있습니다 … 물론 알고리즘이 지정되었습니다.


답변

JDK 1.0 및 1.1과> = 1.2에 대해 뭔가를 발견했습니다.

JDK 1.0.x 및 1.1.x에서 긴 문자열에 대한 hashCode 함수는 모든 n 번째 문자를 샘플링하여 작동했습니다. 이것은 꽤 많은 문자열을 같은 값으로 해싱하여 해시 테이블 조회 속도를 늦출 것을 보장합니다. JDK 1.2에서는 지금까지 결과에 31을 곱한 다음 다음 문자를 순서대로 추가하도록 기능이 개선되었습니다. 이것은 조금 느리지 만 충돌을 피하는 데 훨씬 좋습니다. 출처 : http://mindprod.com/jgloss/hashcode.html

해시 코드 대신 CRC32 또는 MD5를 사용하는 방법과 토론이 필요하지 않습니다.


답변

특정 값과 동일한 해시 코드에 의존해서는 안됩니다. 동일한 실행 내에서 일관된 결과를 반환합니다. API 문서는 다음과 같이 말합니다.

hashCode의 일반적인 계약은 다음과 같습니다.

  • Java 응용 프로그램을 실행하는 동안 동일한 오브젝트에서 두 번 이상 호출 될 때마다 hashCode 메소드는 동일한 정수를 일관되게 리턴해야합니다. 이 정수는 응용 프로그램의 한 실행에서 동일한 응용 프로그램의 다른 실행까지 일관성을 유지할 필요가 없습니다.

편집
String.hashCode ()에 대한 javadoc은 문자열의 해시 코드 계산 방법을 지정하므로이를 위반하면 공개 API 사양을 위반하게됩니다.


답변

위에서 말했듯이 일반적으로 동일하게 유지되는 클래스의 해시 코드에 의존해서는 안됩니다. 동일한 VM 에서 동일한 응용 프로그램 을 계속 실행하더라도 다른 해시 값이 생성 될 수 있습니다. AFAIK Sun JVM의 해시 함수는 모든 실행에서 동일한 해시를 계산하지만 보장되지는 않습니다.

이것은 이론적이지 않습니다. java.lang.String의 해시 함수 는 JDK1.2 에서 변경 되었습니다 (이전 해시는 URL이나 파일 이름과 같은 계층 적 문자열에 문제가있었습니다. 끝에는 다른 문자열에 대해 동일한 해시를 생성하는 경향이있었습니다).

java.lang.String은 hashCode ()의 알고리즘이 문서화되어 있기 때문에 특별한 경우이므로 신뢰할 수 있습니다. 나는 아직도 그것이 나쁜 습관이라고 생각합니다. 특수하고 문서화 된 속성이있는 해시 알고리즘이 필요한 경우 하나만 작성하십시오.


답변

걱정해야 할 또 다른 (!) 문제는 초기 / 늦은 Java 버전간에 구현이 변경 될 수 있다는 것입니다. 구현 세부 사항이 제대로 설정되어 있다고 생각하지 않으므로 향후 Java 버전으로 업그레이드 하면 문제가 발생할 수 있습니다.

결론은의 구현에 의존하지 않을 것입니다 hashCode().

이 메커니즘을 사용하여 실제로 해결하려는 문제를 강조 할 수 있으며보다 적합한 방법이 강조 될 수 있습니다.


답변

질문에 대답하고 토론을 계속하지 마십시오. Apache Harmony JDK 구현은 다른 알고리즘을 사용하는 것 같습니다. 적어도 완전히 다르게 보입니다.

일 JDK

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}

아파치 하모니

public int hashCode() {
    if (hashCode == 0) {
        int hash = 0, multiplier = 1;
        for (int i = offset + count - 1; i >= offset; i--) {
            hash += value[i] * multiplier;
            int shifted = multiplier << 5;
            multiplier = shifted - multiplier;
        }
        hashCode = hash;
    }
    return hashCode;
}

직접 확인하십시오 …


답변

변경 사항과 호환되지 않는 VM이 ​​걱정되는 경우 기존 해시 코드 구현을 고유 한 유틸리티 클래스에 복사하여 해시 코드를 생성하십시오.