자바 의 hashcode 를 자세히 설명 합 니 다.

11235 단어 Javahashcode
뭐 공부 해요?
Hash,일반적으로 산열,잡기,또는 음역 을 해시 로 번역 합 니 다.임의의 길이 의 입력(프 리 맵 pre-image 라 고도 함)을 산열 알고리즘 을 통 해 고정 길이 의 출력 으로 변환 합 니 다.이 출력 은 산열 값 입 니 다.이러한 전환 은 압축 맵 이다.즉,해시 값 의 공간 은 보통 입력 공간 보다 훨씬 작 고 서로 다른 입력 은 같은 출력 으로 해시 될 수 있 기 때문에 해시 값 에서 유일한 입력 값 을 확정 할 수 없다.쉽게 말 하면 임의의 길이 의 메 시 지 를 일정한 길이 의 메시지 요약 으로 압축 하 는 함수 입 니 다.
이것 은 약간 공식 적 으로 말 하면 키 로 간단하게 이해 할 수 있 습 니 다.마치 맵 의 키 값 처럼 중복 할 수 없습니다.
2.hash 는 무슨 소 용이 있 습 니까?어디서 사용 합 니까?
1.산 목록 에서
2.map 집합
여기 서 간단 한 소 개 를 했 을 뿐 사실은 그렇게 간단 하지 않 습 니 다.예 를 들 어 알고리즘 안의 산 목록,산열 함수,그리고 map 의 중복 할 수 없 는 것 이 도대체 어떻게 판단 하 는 지,그리고 hash 충돌 하 는 문 제 는 모두 hash 값 과 관 계 를 끊 을 수 없습니다.
3.자바 에서 String 류 의 hashcode 방법

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
String 류 의 hashcode 방법 은'char 유형의 방식'을 통 해 추가 되 는 것 을 볼 수 있 습 니 다.String 류 의 바 텀 은 char 배열 을 통 해 이 루어 지기 때 문 입 니 다.
예:String str="ab"; char char[] str={'a','b'};예:문자열 String star="ab";그러면 그 가 대응 하 는 hash 값 은 3105 이다.
어떻게 계산 해 냈 지?val[0]='a' ; val[1]='b'a 에 대응 하 는 Ascall 코드 값 은:97 입 니 다.
b.맞 는 Ascall 코드 값 은:98 입 니 다.
그러면 다음 코드 의 순환 을 거 쳐

 for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
결과:97*31+98=3105;
우리 다시 보기:int h=hash;이 코드 는 왜 가끔 hashcode 방법 으로 되 돌아 오 는 hash 값 이 마이너스 입 니까?
이 문자열 이 길 면?그러면 h 의 값 은 int 유형의 최대 치 를 초과 할 것 입 니 다.만약 에 int 유형의 최대 치 를 초과 하면 그의 범 위 를 초과 하면 어떻게 될 지 생각해 본 적 이 있 습 니까?
우 리 는 먼저 이런 간단 한 코드 를 보 았 다.

 int count=0;
    while (true){
   if (count++<10){
            System.out.println("hello world");
          
        }
    }
헬 로 월 드 가 몇 번 을 수출 할 것 같 아 요?
정상 적 인 상황 에서 count 가 10 보다 작 으 면 출력 이 안 되 는 거 죠?
그러나 사실은 그렇지 않다.이것 은 사 순환 이라는 것 을 명확 하 게 알려 준다.
count 가 계속 추가 되 었 기 때문에 처음에 if 가 성립 되 었 고 뒤의 if 가 성립 되 지 않 았 으 며 나중에 if 가 다시 성립 되 었 습 니 다.왜 성립 되 었 습 니까?카운트 가 마이너스 로 바 뀌 었 기 때문이다.
???? 왜?count 는 줄곧 무제 한의 플러스 이기 때문에 선형 성장 이기 때문에 계산 속도 가 매우 빠 르 기 때문에 얼마 지나 지 않 아 int 유형의 최대 치 를 초과 할 것 이다.출력 을 제어 하 는 count 가 마이너스 로 바 뀌 었 기 때문에 이때 if 조건 이 또 성립 되 었 습 니 다.
在这里插入图片描述
먼저 다음 int 의 범 위 를 살 펴 보 겠 습 니 다.int 는 4 개의 바이트 이 고 하나의 바이트 는 8 비트 이 며 하나의 int 값 은 필요 한 저장 공간 은 32 비트 입 니 다.그런데 요?이것 은 기호 비트 가 있 는 int 입 니 다.정수 와 음 수 를 나타 내 는 기호 비트 가 필요 합 니 다.
int 값 의 범 위 는:-2^31 ~ 2^31즉:-2147483648 에서 21474833647 이다.
int 최대 값 에 대응 하 는 바 이 너 리 는 맞 습 니까?
在这里插入图片描述
다 1 이 야?2147483647 의 최대 치 는 정수 가 아 닙 니까?1 위 는 0 으로 해 야 되 는 거 아니 야?
이때 이 0 은 쓰 지 않 은 것 을 생략 한 것 이다.바 이 너 리 시스템 은 패 치 를 통 해 데 이 터 를 저장 하기 때문이다.첫 번 째 는 기호 위치 이 고 0 은 플러스 이 며 1 은 마이너스 이다.플러스 는 기호 위치 가 모두 1 인 것 을 제외 하고 1 을 더 하면 진 위 를 한다.기호 위 치 는 1 이 되 고 마이너스 이 며 다른 것 은 0 이다.
그 러 니까 int 의 최대 값 에 1 을 더 하면'최소 값'으로 변 합 니 다.
자!말 로 는 증거 가 없고 설득력 이 없다.우 리 는 코드 를 직접 보 았 다.
在这里插入图片描述
그렇다면 우 리 는 반대로 최소 치 를 1 로 줄 일 까?그럼 대응 하 는 게 우리 int 타 입의 최대 치 아 닙 니까?
이것 을 자세히 보면 왜 hashcode 방법 이 호출 될 때 는 양수 이 고,때로는 마이너스 인지 알 수 있 겠 지?그래서 밑바닥 은 재 미 있 습 니 다.예 를 들 어 앞으로 빅 데이터 개발 을 하려 면 이런 데이터 유형의 범위 와 그의 변화 규칙 을 깊이 이해 해 야 합 니 다.그렇지 않 으 면 자신 도 모 르 게 실 수 를 할 때 가 있 습 니 다.당신 은 아직도 잘못 이 어디 에 있 는 지 모 릅 니까?심각 하면 정밀도 가 떨 어 지고 결과 가 예상 한 결과 와 크게 다 를 수 있다 는 것 이다.1 을 더 했 기 때문에 결과 와 예상 결과 가 십 만 팔 천 리 차이 가 났 다.
이것 은 String 류 의 hashcode 방법의 구체 적 인 실현 과정 입 니 다.
4.두 대상 의 hashCode()가 같 으 면 equals()도 반드시 true 입 니 다.맞 습 니까?
일단 은 요?이것 은 틀림없이 옳지 않다.
이 두 가지 방법 은 모두 다시 쓸 수 있 기 때문에 자신의 유형 이 라면 유연 하 게 다시 쓸 수 있 고 jdk 자신의 유형 이 라면 그 가 이 두 가지 방법 을 다시 쓸 수 있 는 지 없 는 지 를 봐 야 한다.
우 리 는 String 류 의 equlas 방법 을 예 로 들 면,equlas 방법 이 다시 쓰 지 않 으 면 Object 류 의 equlas 방법 을 계승 하고,기본적으로 두 대상 의 메모리 주 소 를 비교 합 니 다.다시 쓰 면,우리 가 다시 쓰 는 규칙 에 따라 두 대상 이 같은 지 비교 합 니 다.
다음은 jdkString 클래스 에서 자신 이 다시 쓰 는 equals 방법 입 니 다.

 public boolean equals(Object anObject) {
    //     String               true
        if (this == anObject) {
            return true;
        }
       //                     char     ,       ,      true,        ,    false,             ,     ,              
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
String 의 hashcode 방법 을 살 펴 보 자.바로 우리 가 방금 말 한 그 방법 이다.

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
1:두 String 형식의 대상 메모리 주소 가 같 으 면 true 로 돌아 갑 니 다.
2:두 문자열 의 모든 char 형식의 데 이 터 를 비교 합 니 다.모두 일치 하면 true 로 돌아 가 는 것 입 니 다.하나 가 다 르 면 false 로 돌아 가 고 두 문자열 의 길이 가 같 아야 합 니 다.다 르 면 값 이 같 을 수 없 잖 아 요.
이 를 통 해 알 수 있 듯 이 equals 방법 이 true 로 돌아 가 는 지 여 부 는 hashcode 방법 과 반 마 오 관계 가 없 잖 아 요.
다음은 사용자 정의 대상 을 보 겠 습 니 다.속성 id 와 name 이 있 는 User 클래스 를 만 들 겠 습 니 다.

public class User {
    int id;
    String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }


}
hashcode 방법 과 equals 방법 을 다시 쓰 지 않 은 상태 에서 비교 하기:

 User user1 = new User();
        User user2 = new User();

        System.out.println(user1.hashCode());
        System.out.println(user2.hashCode());
        System.out.println(user1.equals(user2));
在这里插入图片描述
해답:우 리 는 다시 쓰 지 않 았 기 때문에 이 두 가지 방법 은 모두 Object 류 에서 계승 한 것 입 니 다.그래서 요?비교 하 는 것 은 메모리 주소 입 니 다.우 리 는 new 방식 으로 두 user 대상 을 만 들 었 기 때문에 그들의 메모리 주 소 는 분명 다 를 것 입 니 다.그래서 false 로 돌아 갑 니 다.hashcode 방법 은 자바 의 바 텀 언어 c++로 썼 습 니 다.구체 적 으로 그 내부 가 어떻게 실현 되 었 는 지,포장 되 었 는 지 저도 알 수 없습니다.나중에 다시 알 아 보 겠 습 니 다.어떤 사람 은 메모리 주소 와 관련 이 있다 고 말 하지만 구체 적 으로 나 는 구체 적 으로 실현 되 는 것 을 보지 못 했 고 동의 할 수도 없 었 다.어떤 것 은 자신 이 끊임없이 모색 하고 자신 이 직접 실천 해 야 하 며 다른 사람 이 말 하 는 것 을 믿 지 말 아야 한다.
알 겠 습 니 다.다음은 User 류 의 hashcode 방법 을 다시 쓰 겠 습 니 다.

public class User {
    int id;
    String name;



    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }



    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}
在这里插入图片描述
보 이 는 것 은 우리 두 User 대상 의 hashcode 방법 이 되 돌아 오 는 hash 값 이 완전히 일치 하지만 equals 방법 으로 비교 하 는 것 입 니까?false 입 니까?그래서 두 대상 의 hashcode 방법 이 되 돌아 오 는 hash 값 이 같 고 equlas 도 반드시 true 로 돌아 가 는 것 은 완전히 성립 되 지 않 고 직접 뒤 집 는 것 입 니 다.
다음 에 우 리 는 equlas 방법 을 다시 쓰 겠 습 니 다.이때 우 리 는 두 대상 의 id 와 name 이 모두 같 으 면 이 두 대상 은 같은 대상 이 라 고 규정 합 니 다.그리고 방금 우리 가 다시 쓴 hashcode 방법 을 삭제 합 니 다.

public class User {
    int id;
    String name;

    public User(int i, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                name.equals(user.name);
    }


}
在这里插入图片描述
실행 결 과 를 통 해 우 리 는 hashcode 방법 이 되 돌아 오 는 hash 값 이 일치 하지 않 음 을 알 수 있 습 니 다.그러나 우리 의 equlas 방법 은 여전히 true 로 되 돌아 갑 니 다.이 equlas 방법 은 우리 가 다시 쓴 것 이기 때 문 입 니 다.호출 할 때 Object 의 equlas 방법 을 제거 하지 않 고 메모리 주소 보다 우리 의 재 작성 규칙 에 따라: user id name , .그래서 여기까지..당신 은 hashcode 방법 과 equlas 간 의 관 계 를 구체 적 으로 이해 하 였 습 니까?
아직도 모 르 겠 으 면 다시 한 번 보 겠 습 니 다.저 희 는 지금 User 류 의 equlas 방법 과 hashcode 방법 을 모두 쓰 고 있 습 니 다.그런데 요?나 는 두 i 의 다른 User 대상 을 만 들 것 이다(즉,id 와 name 이 모두 다르다).

public class User {
    int id;
    String name;

    public User(int i, String name) {
        this.id = id;
        this.name = name;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id &&
                name.equals(user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}
在这里插入图片描述
이 를 통 해 알 수 있 듯 이 hashcode 방법 으로 돌아 오 는 hash 값 은 같 지만 equlas 방법 으로 비교 하면 돌아 오 는 것 은 false 입 니 다.
여기 서 우리 가 말 하 는 것 은 좀 수 다스 럽 습 니 다.원래 두 세 마디 로 분명하게 말 할 수 있 는데 초보 친구 가 이해 하지 못 할 까 봐 몇 마디 더 했 습 니 다.이 글 은 제 개인 적 인 이해 입 니 다.만약 에 정확 하지 않 은 희망 이 있 으 면 참고서 와 홈 페이지 를 비교 해 보 세 요.눈 으로 본 것 이 사실 이 니까 저도 제 가 옳다 는 것 을 완전히 보장 할 수 없습니다.
자바 의 hashcode 에 대한 자세 한 설명 은 여기까지 입 니 다.자바 hashcode 에 관 한 더 많은 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기