자바 에서 hashcode 와 equal 상세 설명

10748 단어 자바
1. 우선 equals () 와 hashcode () 두 가지 방법 은 모두 object 류 에서 계승 되 었 다.
equals () 방법 은 object 클래스 에서 다음 과 같이 정의 합 니 다.
자바 코드 

public boolean equals(Object obj) { 
   return (this == obj); 
} 


두 대상 의 주소 값 을 비교 한 것 이 분명 하 다.하지만 String, Math, 그리고 Integer, Double...이러한 패 키 징 클래스 가 equals () 방법 을 사용 할 때 object 류 의 equals () 방법 을 덮어 썼 습 니 다.예 를 들 어 String 클래스 에서 다음 과 같 습 니 다.
자바 코드 

public boolean equals(Object anObject) { 
if (this == anObject) { 
    return true; 
} 
if (anObject instanceof String) { 
    String anotherString = (String)anObject; 
    int n = count; 
    if (n == anotherString.count) { 
char v1[] = value; 
char v2[] = anotherString.value; 
int i = offset; 
int j = anotherString.offset; 
while (n-- != 0) { 
    if (v1[i++] != v2[j++]) 
return false; 
} 
return true; 
    } 
} 
return false; 
} 

이것 은 더 이상 주소 의 비교 가 아니 라 진행 되 는 내용 비교 임 이 분명 하 다.순서대로 Double, Integer, Math...등등 이런 종 류 는 모두 equals () 방법 을 다시 써 서 내용 의 비 교 를 진행 했다.물론 기본 유형 은 값 을 비교 하 는 것 이 니 할 말 이 없다.
자바 언어 가 equals () 에 대한 요 구 는 다음 과 같 습 니 다. 이러한 요 구 는 반드시 지 켜 야 합 니 다.
대칭 성: x. equals (y) 가 'true' 로 되 돌아 오 면 y. equals (x) 도 'true' 로 되 돌아 가 야 합 니 다.
반사 성: x. equals (x) 는 'true' 로 되 돌아 가 야 합 니 다.
유추 성: x. equals (y) 가 'true' 로 되 돌아 가 고 y. equals (z) 가 'true' 로 되 돌아 오 면 z. equals (x) 도 'true' 로 되 돌아 가 야 합 니 다.
그리고 일치 성: 만약 에 x. equals (y) 가 'true' 로 되 돌아 오 면 x 와 y 의 내용 이 변 하지 않 으 면 x. equals (y) 를 몇 번 반복 하 든 되 돌아 오 는 것 은 'true' 입 니 다.
어떠한 경우 에 도 x. equals (null) 는 영원히 "false" 로 돌아 갑 니 다.x. equals (x 와 다른 유형의 대상) 는 영원히 "false" 로 돌아 갑 니 다.
이 다섯 가 지 는 이퀄 스 (equals) 방법 을 다시 쓸 때 반드시 지 켜 야 하 는 준칙 이 며, 위반 시 예상 치 못 한 결과 가 나 올 수 있 으 니 꼭 지 켜 주시 기 바 랍 니 다.
2. 그 다음은 hashcode () 방법 으로 object 류 에서 다음 과 같이 정의 합 니 다.
자바 코드

 public native int hashCode(); 

설명 은 현지 방법 으로 그것 의 실현 은 현지 기계 와 관련 된 것 이다.물론 우 리 는 자신 이 쓴 클래스 에 hashcode () 방법 을 덮어 쓸 수 있 습 니 다. 예 를 들 어 String, Integer, Double...등등 이 종 류 는 모두 hashcode () 방법 을 덮어 쓴 것 입 니 다.예 를 들 어 String 클래스 에서 정의 하 는 hashcode () 방법 은 다음 과 같 습 니 다.
자바 코드
 
   
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; 
} 

이 프로그램 을 설명 합 니 다 (String 의 API 에 기 록 됨).
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
int 알고리즘 을 사용 합 니 다. 여기 s [i] 는 문자열 의 i 번 째 문자 입 니 다. n 은 문자열 의 길이 입 니 다. ^ 는 구 미 를 표시 합 니 다.(빈 문자열 의 해시 코드 는 0 입 니 다.)
3. 여기 서 우 리 는 먼저 한 가지 문 제 를 알 아야 한다.
equals () 가 같은 두 대상 은 hashcode () 가 반드시 같 습 니 다.
equals () 가 같 지 않 은 두 대상 은 그들의 hashcode () 가 같 지 않다 는 것 을 증명 할 수 없다.다시 말 하면 equals () 방법 이 같 지 않 은 두 대상 은 hashcode () 가 같 을 수 있다.(내 이 해 는 해시 코드 가 생 성 될 때 충돌 이 생 겨 서 생 긴 것 이다.)
반대로: hashcode () 가 다 르 면 반드시 equals () 를 내 놓 을 수 있 고 다 를 수 있 습 니 다.hashcode () 가 같 을 수도 있 고 equals () 가 같 을 수도 있 고 다 를 수도 있 습 니 다.세 번 째 사용 범 위 를 설명 하 겠 습 니 다. 제 이 해 는 object, String 등 종류 에서 모두 사용 할 수 있다 는 것 입 니 다.object 클래스 에서 hashcode () 방법 은 로 컬 방법 으로 대상 의 주소 값 을 되 돌려 줍 니 다. object 클래스 의 equals () 방법 은 두 대상 의 주소 값 을 비교 합 니 다. equals () 가 같 으 면 두 대상 의 주소 값 도 같 습 니 다. 물론 hashcode () 도 같 습 니 다.String 클래스 에서 equals () 는 두 대상 의 내용 을 비교 하고 두 대상 의 내용 이 같 을 때
Hashcode () 방법 은 String 류 의 재 작성 (두 번 째 점 에서 분 석 된) 코드 에 대한 분석 에 따라 hashcode () 가 결 과 를 되 돌려 주 는 것 도 같다 는 것 을 알 수 있 습 니 다.이 를 통 해 Integer, Double 등 패 키 징 류 에서 재 작성 한 equals () 와 hashcode () 방법 도 이 원칙 에 적합 하 다 는 것 을 알 수 있다.물론 재 작성 을 거치 지 않 은 클래스 는 object 류 의 equals () 와 hashcode () 방법 을 계승 한 후에 도 이 원칙 을 준수 합 니 다.
4. hashcode () 와 equals () 에 대해 서 는 hashset, hashmap, hashtable 의 사용 을 언급 하지 않 을 수 없습니다. 구체 적 으로 어떻게 되 는 지 다음 과 같은 분석 을 보십시오.
Hashset 은 Set 인 터 페 이 스 를 계승 하고 Set 인 터 페 이 스 는 Collection 인 터 페 이 스 를 실현 하 는 차원 관계 입 니 다.그럼 hashset 은 어떤 원리 에 따라 대상 을 액세스 합 니까?
hashset 에 서 는 중복 대상 이 나타 나 지 않 고 요소 의 위치 도 불확실 합 니 다.hashset 에 서 는 요소 가 중복 되 는 지 여 부 를 어떻게 판단 합 니까?이것 이 바로 문제 의 관건 이다. 오후 내 내 조 회 를 통 해 증 거 를 구 하 는 것 이 마침내 약간의 시사 점 을 얻 었 다. 여러분 과 공유 해 보 자. 자바 의 집합 에서 두 대상 이 같은 지 판단 하 는 규칙 은:
1) 두 대상 의 hashCode 가 동일 한 지 판단
같 지 않 으 면, 두 상대 도 같 지 않다 고 생각 하고, 이상.
같 으 면 2)
(이 점 은 저장 효율 을 높이 기 위해 요구 하 는 것 일 뿐 이론 적 으로 없어 도 되 지만 없 으 면 실제 사용 할 때 효율 이 크게 떨 어 지기 때문에 우 리 는 이 를 필요 로 한다. 그 다음 에 이 문 제 를 중점적으로 이야기 할 것 이다.)
2) 두 대상 이 equals 로 연산 하 는 것 이 동일 한 지 판단
만약 같 지 않다 면, 두 상대 도 같 지 않다 고 생각한다.
만약 같다 면, 두 대상 이 같다 고 생각 하 는 것 (equals () 은 두 대상 이 같은 지 아 닌 지 를 판단 하 는 관건)
왜 두 가지 준칙 인 데, 설마 첫 번 째 준칙 을 쓰 면 안 되 겠 는가?안 됩 니 다. 앞에서 말 했 듯 이 hashcode () 가 같 을 때 equals () 방법 도 다 를 수 있 기 때문에 제2 조 준칙 으로 제한 해 야 중복 되 지 않 는 요 소 를 추가 할 수 있 습 니 다.
예 를 들 어 다음 코드:
자바 코드
     
public static void main(String args[]){ 
String s1=new String("zhaoxudong"); 
String s2=new String("zhaoxudong"); 
System.out.println(s1==s2);//false 
System.out.println(s1.equals(s2));//true 
System.out.println(s1.hashCode());//s1.hashcode()  s2.hashcode() 
System.out.println(s2.hashCode()); 
Set hashset=new HashSet(); 
hashset.add(s1); 
hashset.add(s2); 
/*      s1,s2 ,           ,    hashset  s1 s2    ,        ,   s2   s1;*/ 

자바 코드
   
        Iterator it=hashset.iterator(); 
            while(it.hasNext()) 
            { 
             System.out.println(it.next()); 
            } 
 
마지막 으로 while 순환 할 때 'zhaoxudong' 만 인쇄 되 었 습 니 다.
출력 결과: false
true
-967303459
-967303459
이 는 String 류 가 equals () 방법 과 hashcode () 방법 을 다시 썼 기 때문에 위의 1.2 조 원칙 에 따라 정 해진 시간 에 hashset 은 이들 이 같은 대상 이 라 고 생각 하고 중복 추 가 했 습 니 다.
하지만 아래 절 차 를 보면:
자바 코드
    
import java.util.*; 
public class HashSetTest 
{ 
   public static void main(String[] args) 
    { 
                 HashSet hs=new HashSet(); 
                 hs.add(new Student(1,"zhangsan")); 
                 hs.add(new Student(2,"lisi")); 
                 hs.add(new Student(3,"wangwu")); 
                 hs.add(new Student(1,"zhangsan")); 
  
                 Iterator it=hs.iterator(); 
                 while(it.hasNext()) 
                 { 
                        System.out.println(it.next()); 
                 } 
     } 
} 
class Student 
   { 
     int num; 
     String name; 
     Student(int num,String name) 
                { 
                this.num=num; 
                 this.name=name; 
                 } 
              public String toString() 
                { 
                    return num+":"+name; 
                 } 
           } 

     출력 결 과 는:
1:zhangsan
1:zhangsan
3:wangwu
2:lisi
문제 가 생 겼 습 니 다. 왜 hashset 에 똑 같은 요 소 를 추 가 했 습 니까? 이것 은 hashset 의 원칙 과 어 긋 나 는 것 이 아 닙 니까?없다
hashcode () 에 따라 두 번 만 든 new Student (1, "zhangsan") 대상 을 비교 할 때 서로 다른 해시 코드 값 이 생 성 되 기 때문에 hashset 은 그 를 다른 대상 으로 대 했다. 물론 이때 equals () 방법 이 되 돌아 오 는 값 도 다르다.그렇다면 왜 다른 해시 코드 값 이 생 성 되 었 을 까?위 에서 저희 가 s1 과 s2 를 비교 할 때 같은 해시 코드 를 만 들 지 않 았 나 요?그 이 유 는 우리 가 쓴 Student 클래스 가 자신의 hashcode () 와 equals () 방법 을 다시 만 들 지 않 았 기 때 문 입 니 다. 그래서 비교 할 때 계승 하 는 object 클래스 의 hashcode () 방법 입 니 다. 하하, 여러분 은 object 류 의 hashcode () 방법 이 무엇 인지 기억 하 시 죠?!
이것 은 로 컬 방법 입 니 다. 대상 의 주소 (주소 참조) 를 비교 하고 new 방법 으로 대상 을 만 듭 니 다. 두 번 생 성 된 것 은 당연히 다른 대상 입 니 다. (이것 은 모두 가 이해 할 수 있 습 니 다...) 결 과 는 두 대상 의 hashcode () 가 돌아 오 는 값 이 다 릅 니 다.그래서 첫 번 째 준칙 에 따라 hashset 은 이들 을 서로 다른 대상 으로 대 할 것 이 고 두 번 째 준칙 으로 판단 할 필요 가 없다.그럼 이 문 제 는 어떻게 해결 합 니까?
정 답 은 Student 클래스 에서 다시 hashcode () 와 equals () 방법 입 니 다.
예 를 들 면:
자바 코드 
 

class Student 
{ 
int num; 
String name; 
Student(int num,String name) 
{ 
            this.num=num; 
            this.name=name; 
} 
public int hashCode() 
{ 
            return num*name.hashCode(); 
} 
public boolean equals(Object o) 
{ 
            Student s=(Student)o; 
            return num==s.num && name.equals(s.name); 
} 
public String toString() 
{ 
            return num+":"+name; 
} 
} 


재 작성 방법 에 따 르 면 뉴 스 튜 던 트 (1, "zhangsan") 를 두 번 호출 하 더 라 도 대상 의 해시 코드 를 얻 었 을 때 재 작성 방법 인 hashcode () 에 따라 얻 은 해시 코드 는 똑 같 을 것 입 니 다.
물론 equals () 방법 에 따라 우리 도 동일 하 다 고 판단 할 수 있다.그래서 hashset 집합 에 추가 할 때 중복 요소 로 보 았 습 니 다.그래서 수 정 된 프로그램 을 실행 할 때 실행 결 과 는 다음 과 같 습 니 다.
1:zhangsan
3:wangwu
2:lisi
중복 요소 의 문제 가 제거 되 었 음 을 볼 수 있다.
hibenate 의 pojo 클래스 에서 다시 equals () 와 hashcode () 에 대한 질문:
1) 중요 한 것 은 equals 입 니 다. hashCode 를 다시 쓰 는 것 은 기술적 인 요구 일 뿐 입 니 다 (효율 을 높이 기 위해)
2) 왜 equals 를 다시 써 야 합 니까? 자바 의 집합 프레임 워 크 에 서 는 equals 를 통 해 두 대상 이 같은 지 여 부 를 판단 하기 때 문 입 니 다.
3) hibenate 에 서 는 관련 대상 을 저장 하기 위해 set 집합 을 자주 사용 하 며, set 집합 은 중복 되 지 않 습 니 다.앞에서 언급 한 hashset 집합 에 요 소 를 추가 할 때 대상 이 똑 같은 지 아 닌 지 를 어떻게 판단 하 는 지 에 대해 이야기 하 겠 습 니 다. 앞에서 두 가 지 를 말 했 는데 사실은 equals () 라 는 것 만 다시 써 도 됩 니 다.
그러나 hashset 에서 요소 가 비교적 많 거나 재 작성 한 equals () 방법 이 복잡 할 때 우 리 는 equals () 방법 으로 만 비교 판단 하고 효율 도 매우 낮 기 때문에 hashcode () 라 는 방법 을 도입 했다. 단지 효율 을 높이 기 위해 서 일 뿐 이지 만 나 는 이것 이 매우 필요 하 다 고 생각한다. (그래서 우 리 는 앞에서 두 가지 준칙 으로 hashset 의 요소 가 중복 되 는 지 여 부 를 판단 한다)。
예 를 들 어 이렇게 쓸 수 있다.
public int hashCode(){
return 1;} / / hashcode 와 같은 값 이 잘못 되 었 습 니 다.
이렇게 하 는 효 과 는 해시 코드 를 비교 할 때 판단 할 수 없다 는 것 이다. 모든 대상 이 돌아 오 는 해시 코드 는 1 이기 때문에 매번 equals () 방법 을 비교 해 야 중복 여 부 를 판단 할 수 있 기 때문에 효율 이 크게 떨 어 질 수 밖 에 없다.
저 는 앞에서 언급 한 것 처럼 hashset 에서 요소 가 중복 되 는 지 판단 하 는 필요 한 방법 이 equals () 방법 (인터넷 에서 찾 은 관점 에 따라) 이 라면 하 쉬 표 에 관 한 문 제 는 언급 되 지 않 았 습 니 다. 그런데 이 집합 은 hashset 이 라 고 합 니 다. 이것 은 무엇 입 니까?
나 는 hashmap, hashtable 에서 의 저장 작업 은 여전히 위의 준칙 을 준수 하고 있다 고 생각한다.그 러 니까 더 이상 말 안 할 게.이것들 은 오늘 책 을 읽 고 인터넷 에서 자 료 를 조회 하 며 스스로 정리 한 것 이다. 일부 코드 와 언어 는 인용 한 것 이지 만 자신 이 정리 한 것 이 확실 하 다.잘못된 점 과 상세 하지 않 은 점 이 있 으 면 지적 해 주세요. 저도 초보 자 이기 때문에 잘못된 점 이 있 을 수 있 으 니 함께 토론 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기