자바 의 hashcode 를 자세히 설명 합 니 다.
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 에 관 한 더 많은 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.