Development Tip

hashCode ()가 재정의되지 않은 경우 객체의 해시 코드는 무엇입니까?

yourdevel 2020. 11. 24. 19:58
반응형

hashCode ()가 재정의되지 않은 경우 객체의 해시 코드는 무엇입니까?


hashCode () 메서드가 재정의되지 않은 경우 Java의 모든 개체에서 hashCode ()를 호출 한 결과는 무엇입니까?


일반적으로 hashCode ()는 재정의하지 않으면 메모리에있는 객체의 주소를 반환합니다.

1 부터 :

합리적으로 실용적인만큼 Object 클래스에 의해 정의 된 hashCode 메서드는 고유 한 개체에 대해 고유 한 정수를 반환합니다. (이것은 일반적으로 객체의 내부 주소를 정수로 변환하여 구현되지만 JavaTM 프로그래밍 언어에서는이 구현 기술이 필요하지 않습니다.)


HotSpot JVM에서는 기본적으로 오버로드되지 않은 첫 번째 호출시 Object.hashCode또는 System.identityHashCode임의의 숫자가 생성되어 개체 헤더에 저장됩니다. 결과적으로 헤더에서이 값을 호출 Object.hashCode하거나 System.identityHashCode추출합니다. 기본적으로 객체 내용이나 객체 위치와 공통점이 없으며 난수 만 있습니다. 이 동작은 -XX:hashCode=n가능한 값이 다음과 같은 HotSpot JVM 옵션에 의해 제어됩니다 .

  • 0 : 글로벌 랜덤 생성기를 사용합니다. 이것은 Java 7의 기본 설정입니다. 여러 스레드의 동시 호출로 인해 경쟁 조건이 발생하여 다른 객체에 대해 동일한 hashCode가 생성 될 수 있다는 단점이 있습니다. 또한 동시성이 높은 환경에서는 경합 (다른 CPU 코어의 동일한 메모리 영역 사용)으로 인해 지연이 발생할 수 있습니다.
  • 5 : 이전의 단점이없는 스레드 로컬 xor-shift 랜덤 생성기를 사용합니다. 이것은 Java 8의 기본 설정입니다.
  • 1 : "stop-the-world"이벤트에서 변경되는 임의의 값과 혼합 된 개체 포인터를 사용하므로 stop-the-world 이벤트 (예 : 가비지 수집)간에 생성 된 hashCode가 안정적입니다 (테스트 / 디버깅 목적).
  • 2 : 항상 사용 1(테스트 / 디버깅 목적으로)
  • 3 : 자동 증가 번호 사용 (테스트 / 디버깅 목적으로 글로벌 카운터도 사용되므로 경합 및 경쟁 조건이 가능함)
  • 4 : 필요한 경우 32 비트로 잘린 개체 포인터 사용 (테스트 / 디버깅 목적)

을 설정하더라도 -XX:hashCode=4hashCode가 항상 객체 주소를 가리키는 것은 아닙니다. 객체는 나중에 이동할 수 있지만 hashCode는 동일하게 유지됩니다. 또한 객체 주소가 제대로 분산되지 않으므로 (애플리케이션이 메모리를 많이 사용하지 않는 경우 대부분의 객체가 서로 가까이 위치하게됩니다)이 옵션을 사용하면 해시 테이블이 불균형해질 수 있습니다.


의 구현은 hashCode()클래스마다 다를 수 있지만 계약 hashCode()은 매우 구체적이며 Javadocs 에 명확하고 명시 적으로 명시되어 있습니다 .

객체의 해시 코드 값을 반환합니다. 이 메소드는 java.util.Hashtable에서 제공하는 것과 같은 해시 테이블의 이점을 위해 지원됩니다.

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

  • Java 응용 프로그램을 실행하는 동안 동일한 객체에서 두 번 이상 호출 될 때마다 객체의 같음 비교에 사용 된 정보가 수정되지 않으면 hashCode 메서드는 일관되게 동일한 정수를 반환해야합니다. 이 정수는 애플리케이션의 한 실행에서 동일한 애플리케이션의 다른 실행까지 일관성을 유지할 필요가 없습니다.
  • equals (Object) 메서드에 따라 두 객체가 같으면 두 객체 각각에 대해 hashCode 메서드를 호출하면 동일한 정수 결과가 생성되어야합니다.
  • equals (java.lang.Object) 메소드에 따라 두 객체가 같지 않은 경우 두 객체 각각에 대해 hashCode 메소드를 호출하면 고유 한 정수 결과가 생성되어야하는 것은 아닙니다. 그러나 프로그래머는 같지 않은 개체에 대해 고유 한 정수 결과를 생성하면 해시 테이블의 성능이 향상 될 수 있음을 알고 있어야합니다.

합리적으로 실용적인만큼 Object 클래스에 의해 정의 된 hashCode 메서드는 고유 한 개체에 대해 고유 한 정수를 반환합니다. (이것은 일반적으로 객체의 내부 주소를 정수로 변환하여 구현되지만 JavaTM 프로그래밍 언어에서는이 구현 기술이 필요하지 않습니다.)

hashCode()밀접하게 연결되어 equals()있으며 재정의하는 경우 equals()에도 재정의해야합니다 hashCode().


해시 코드가 재정의되지 않은 경우 Object의 해시 코드를 호출합니다. 다음은 javadoc에서 발췌 한 것입니다.

합리적으로 실용적인만큼 Object 클래스에 의해 정의 된 hashCode 메서드는 고유 한 개체에 대해 고유 한 정수를 반환합니다. (이것은 일반적으로 객체의 내부 주소를 정수로 변환하여 구현되지만 JavaTM 프로그래밍 언어에서는이 구현 기술이 필요하지 않습니다.)


기본 해시 코드 구현은 jvm에있는 객체의 내부 주소를 32 비트 정수로 제공합니다. 따라서 두 개의 다른 (메모리에있는) 개체는 다른 해시 코드를 갖습니다.

이것은 equals의 기본 구현과 일치합니다. 객체의 같음을 재정의하려면 hashCode가 일관성이 있도록 조정해야합니다.

좋은 개요는 http://www.ibm.com/developerworks/java/library/j-jtp05273.html참조 하십시오 .


equals를 재정의하는 모든 클래스에서 hashCode를 재정의해야합니다. 그렇게하지 않으면 Object.hashCode에 대한 일반 계약을 위반하여 클래스가 conjunction with all hash-based collections에서 제대로 작동하지 못하게됩니다 .including HashMap, HashSet, and Hashtable.


다른 개체가 다른 결과를 제공하도록 해시 코드를 구현해야합니다. 나는 이것을하는 표준 방법이 있다고 생각하지 않습니다.

일부 정보는 이 기사를 읽으십시오 .


해시 코드는 해시 세트와 같은 컬렉션에 개체를 저장하는 데 유용합니다. Object가 Hashcode를 고유 한 것으로 정의 할 수 있도록함으로써 HashSet의 알고리즘이 효과적으로 작동 할 수 있습니다.

객체 자체는 메모리에서 객체의 주소를 사용합니다. 이는 매우 고유하지만 두 개의 다른 객체 (예 : 두 개의 동일한 문자열)가 메모리에서 복제 되더라도 동일한 것으로 간주되어야하는 경우 그다지 유용하지 않을 수 있습니다.


해시 코드가 다른 두 개체는 equals ()와 관련하여 동일하지 않아야합니다.

a.hashCode() != b.hashCode() 암시해야한다 !a.equals(b)

그러나 equals ()와 관련하여 동일하지 않은 두 객체는 ​​동일한 해시 코드를 가질 수 있습니다. 많은 객체가 동일한 해시 코드를 가지고있는 경우 이러한 객체를 세트 또는 맵에 저장하면 효율성이 떨어집니다.


실제로 대답은 아니지만 이전 의견에 추가

객체의 내부 주소는 가비지 수집기가 힙 압축 중에 이동할 수있는 JVM에서 변경되지 않은 상태로 유지되도록 보장 할 수 없습니다.

나는 다음과 같은 것을 시도했다.

public static void main(String[] args) {
    final Object object = new Object();
    while (true) {
        int hash = object.hashCode();
        int x = 0;
        Runtime r = Runtime.getRuntime();
        List<Object> list = new LinkedList<Object>();
        while (r.freeMemory() / (double) r.totalMemory() > 0.3) {
            Object p = new Object();
            list.add(p);
            x += object.hashCode();//ensure optimizer or JIT won't remove this
        }
        System.out.println(x);
        list.clear();
        r.gc();
        if (object.hashCode() != hash) {
            System.out.println("Voila!");
            break;
        }
    }
}

But the hashcode indeed doesn't change... can someone tell me how Sun's JDK actually implements Obect.hashcode?


returns 6 digit hex number. This is usually the memory location of the slot where the object is addressed. From an algorithmic per-se, I guess JDK does double hashing (native implementation) which is one of the best hashing functions for open addressing. This double hashing scheme highly reduces the possibility of collisions.

The following post will give a supportive idea -

Java - HashMap confusion about collision handling and the get() method

참고URL : https://stackoverflow.com/questions/2237720/what-is-an-objects-hash-code-if-hashcode-is-not-overridden

반응형