equals()방법 과 hashCode()방법 을 자세히 설명 합 니 다.

머리말
자바 의 기본 클래스 Object 는 두 대상 이 같은 지 판단 하 는 방법 을 제공 합 니 다.hashCode()방법 은 대상 의 해시 코드 를 계산 하 는 데 사 용 됩 니 다.equals()와 hashCode()는 모두 final 방법 이 아니 라 다시 쓸 수 있 습 니 다(overwrite).
본 고 는 두 가지 방법 을 사용 하고 다시 쓸 때 주의해 야 할 문제 들 을 소개 했다.
만약 문장 이 당신 에 게 도움 이 된다 고 생각한다 면,좋아요 나 전 재 를 누 르 시 는 것 을 환영 합 니 다.문장 에 누락 된 부분 이 있 으 니,비판 과 시정 을 환영 합 니 다.
목차
1.equal()방법
2.hashCode()방법
1.Object 의 hashCode()
2.hashCode()의 역할
3.String 에서 equals()와 hashCode()의 실현
4.hashCode 를 다시 쓰 는 방법()
1.hashcode()를 다시 쓰 는 원칙
2.hashCode()재 작성 방법
1.equal()방법
 Object 클래스 에서 equals()방법 은 다음 과 같 습 니 다.
public boolean equals(Object obj) {
    return (this == obj);
}

이 를 통 해 알 수 있 듯 이 Object 류 의 실현 은 구분 도가 가장 높 은 알고리즘 을 사용 했다.즉,두 대상 이 같은 대상 이 아니라면 equals()는 반드시 false 로 돌아 갈 것 이다.
클래스 를 정의 할 때 equals()방법 을 다시 쓸 수 있 지만 주의사항 이 있 습 니 다.JDK 는 equals()를 실현 하 는 방법 이 지 켜 야 할 약속 을 설명 했다.
(1)자 반성:x.equals(x)는 true 로 돌아 가 야 합 니 다.
(2)대칭 성:x.equals(y)와 y.equals(x)의 반환 값 은 반드시 같 아야 한다.
(3)전달 성:x.equals(y)는 true 이 고 y.equals(z)도 true 이 며 x.equals(z)는 true 여야 합 니 다.
(4)일치 성:대상 x 와 y 가 equals()에서 사용 하 는 정보 가 변 하지 않 으 면 x.equals(y)값 은 변 하지 않 습 니 다.
(5)null:x 가 null 이 아니 라 y 가 null 이면 x.equals(y)는 false 여야 합 니 다.
2.hashCode()방법
1.Object 의 hashCode()
Object 클래스 의 hashCode()방법 에 대한 설명 은 다음 과 같 습 니 다.
public native int hashCode();

이 를 통 해 알 수 있 듯 이 hashCode()는 native 방법 이 고 반환 값 유형 은 성형 이다.실제로 이 native 방법 은 대상 이 메모리 에 있 는 주 소 를 해시 코드 로 되 돌려 주 며 대상 의 반환 값 이 다 를 수 있 습 니 다.
equals()방법 과 유사 하 며,hashCode()방법 은 다시 쓸 수 있 습 니 다.JDK 에서 hashCode()방법의 역할 과 실현 시의 주의사항 에 대해 설명 했다.
(1)hashCode()는 자바 util.HashMap 와 같은 해시 표 에서 작용 한다.
(2)대상 이 equals()에서 사용 하 는 정보 가 변 하지 않 으 면 hashCode()값 은 변 하지 않 습 니 다.
(3)두 대상 이 equals()방법 으로 동일 하 다 고 판단 하면 hashCode()방법 도 같 아야 한다.
(4)만약 에 두 대상 이 equals()방법 으로 서로 다르다 고 판단 하면 hashCode()를 요구 하지 않 아 도 반드시 같 지 않 아야 한다.그러나 개발 자 들 은 서로 다른 대상 이 서로 다른 hash 코드 를 만들어 해시 표 의 성능 을 향상 시 킬 수 있다 는 것 을 인식 해 야 한다.
2.hashCode()의 역할
전체적으로 말 하면 hashCode()는 해시 표 에서 역할 을 한다.예 를 들 어 HashSet,HashMap 등 이다.
해시 표(예 를 들 어 HashSet,HashMap 등)에 대상 object 를 추가 할 때 먼저 hashCode()방법 으로 object 의 해시 코드 를 계산 합 니 다.해시 코드 를 통 해 object 가 해시 표 에 있 는 위 치 를 직접 찾 을 수 있 습 니 다(일반적으로 해시 코드 가 해시 표 크기 에 남 는 것).이 위치 에 대상 이 없 으 면 object 를 이 위치 에 직접 삽입 할 수 있 습 니 다.이 위치 에 대상(여러 개 있 을 수 있 으 며 링크 를 통 해 이 루어 질 수 있 습 니 다)이 있 으 면 equals()방법 으로 이 대상 들 이 object 와 같 는 지 비교 하고 같 으 면 object 를 저장 할 필요 가 없습니다.같 지 않 으 면,이 대상 을 링크 에 넣 습 니 다.
이것 은 왜 equals()가 같 으 면 hashCode()가 반드시 같 아야 하 는 지 설명 한다.두 대상 이 equals()와 같다 면 해시 표(예 를 들 어 HashSet,HashMap 등)에 한 번 만 나타 나 야 합 니 다.만약 hashCode()가 같 지 않다 면,그것들 은 해시 표 의 다른 위치 로 흩 어 져 있 을 것 이다.해시 표 에 한 번 도 나타 나 지 않 았 다.
실제로 JVM 에서 불 러 온 대상 은 메모리 에 세 부분 을 포함 합 니 다.대상 헤드,인 스 턴 스 데이터,충전.그 중에서 대상 헤드 는 대상 이 속 한 유형 을 가리 키 는 지침 과 Markword 를 포함 하고 Markword 에는 대상 의 GC 세대 별 연령 정보,잠 금 상태 정보 외 에 대상 의 hashcode 도 포함 된다.대상 실례 데 이 터 는 대상 이 진정 으로 저장 한 유효한 정보 이다.충전 부분 은 HotSpot 요구 대상 의 시작 주소 가 8 바이트 의 정수 배 여야 하기 때문에 자리 표시 자 역할 만 합 니 다.
3.String 에서 equals()와 hashCode()의 실현
String 클래스 의 구현 코드 는 다음 과 같 습 니 다.
    private final char value[];
    private int hash; // Default to 0
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        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;
    }
    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 의 데 이 터 는 final 입 니 다.즉,String 대상 이 생 성 되면 수정 할 수 없습니다.String s="hello";s = "world";의 문 구 는 s="World"가 실 행 될 때 문자열 대상 의 값 이"World"로 변 하 는 것 이 아니 라 String 대상 을 새로 만 들 었 습 니 다.s 참조 가 새로운 대상 을 가리 키 고 있 습 니 다.
2.String 클래스 는 hashCode()의 결 과 를 hash 값 으로 캐 시 하여 성능 을 향상 시 킵 니 다.
3.String 대상 equals()와 같은 조건 은 두 사람 이 String 대상 이 고 길이 가 같 으 며 문자열 값 이 똑 같 습 니 다.두 사람 이 같은 대상 이 라 고 요구 하지 않 는 다.
4.String 의 hashCode()계산 공식 은 s[0]*31^(n-1)+s[1]*31^(n-2)+...+s[n-1]
 
hashCode()계산 과정 에서 왜 숫자 31 을 사 용 했 는 지 에 대해 다음 과 같은 이유 가 있 습 니 다.
1.질 수 를 사용 하여 해시 코드 를 계산 하 는데 질 수의 특성 으로 인해 다른 숫자 와 곱 한 후에 계산 결과 의 유일한 확률 이 더욱 크 고 해시 가 충돌 할 확률 이 더욱 적다.
2.사용 하 는 질 이 클 수록 하 쉬 가 충돌 할 확률 이 낮 지만 계산 속도 도 느리다.31 은 해시 충돌 과 성능 의 절충 으로 사실상 실험 관측 의 결과 이다.
3.JVM 은 자동 으로 31 을 최적화 합 니 다.31*i==(i<<5)-i
 4.hashCode 를 다시 쓰 는 방법()
이 절 은 먼저 hashCode()를 다시 쓰 는 방법 이 지 켜 야 할 원칙 을 소개 한 다음 에 통용 되 는 hashCode()를 다시 쓰 는 방법 을 소개 한다.
1.hashcode()를 다시 쓰 는 원칙
앞에서 설명 한 바 와 같이 hashCode 를 다시 쓰 려 면 다음 과 같은 원칙 을 지 켜 야 한 다 는 것 을 알 수 있 습 니 다.
(1)equals()방법 을 다시 쓰 면'두 대상 이 equals()방법 으로 동일 하 게 판단 하면 hashCode()방법 도 동일 해 야 한다'는 조건 이 성립 되 는 지,성립 되 지 않 으 면 hashCode()방법 을 다시 쓴다.
(2)hashCode()방법 은 너무 간단 해 서 는 안 된다.그렇지 않 으 면 해시 충돌 이 너무 많다.
(3)hashCode()방법 은 너무 복잡 해 서 는 안 된다.그렇지 않 으 면 계산 복잡 도가 너무 높 아 성능 에 영향 을 미친다.
2.hashCode()재 작성 방법
에서 간단 하고 통용 되 는 hashCode 알고리즘 A 를 제 시 했 고 성형 변 수 를 초기 화 했다.이 변 수 는 0 이 아 닌 상수 치 를 부여 했다.예 를 들 어 int result=17;B.equals 방법 에서 비교 하 는 모든 도 메 인(equals()에서 사용 하 는 도 메 인 만 선택 한 이 유 는 상기 원칙 의 제1 조 를 확보 하기 위해 서 입 니 다)을 선택 한 다음 에 각 도 메 인의 속성 에 대해 계산 합 니 다.(1)boolean 값 이 라면 f 를 계산 합 니까?1:0(2)byte\char\short\int 라면(int)f(3)long 값 이면 계산(int)(f^(f>>>32)(4)float 값 이면 Float.float ToIntBits(f)(5)double 값 이면 Double.double ToLongBits(f)를 계산 하고 돌아 오 는 결 과 는 long 이 며 규칙(3)으로 log 를 처리 하여 int(6)대상 이 적용 되면equals 방법 에서 재 귀적 호출 비교 방식 을 취하 면 hashCode 에서 도 재 귀적 으로 hashCode 를 호출 하 는 방식 을 취한 다.그렇지 않 으 면 이 필드 에 범례 를 계산 해 야 합 니 다.예 를 들 어 이 필드 의 값 이 null 일 때 hashCode 값 이 0(7)이면 배열 이 라면 모든 요 소 를 단독 도 메 인 으로 처리 해 야 합 니 다.java.util.Arrays.hashCode 방법 은 8 가지 기본 유형 배열 과 인용 배열 의 hashCode 계산 을 포함 하고 알고리즘 은 같 습 니 다.C.마지막 으로 각 필드 의 해시 코드 를 대상 의 해시 코드 에 통합 합 니 다.
 
다음은 하나의 예 를 통 해 설명 한다.이 예 에서 Person 류 는 equals()방법 과 hashCode()방법 을 다시 썼 다.equals()방법 에 서 는 nam e 역 과 age 역 만 사 용 했 기 때문에 hashCode()방법 에서 도 nam e 역 과 age 역 만 계산 합 니 다.
String 형식의 name 도 메 인 에 대해 String 의 hashCode()방법 을 직접 사용 합 니 다.int 형식의 age 필드 에 대해 서 는 이 필드 의 hash 로 직접 값 을 사용 합 니 다.
public class Person {
	private String name;
	private int age;
	private boolean gender;

	public Person() {
		super();
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public boolean isGender() {
		return gender;
	}
	public void setGender(boolean gender) {
		this.gender = gender;
	}

	@Override
	public boolean equals(Object another) {
		if (this == another) {
			return true;
		}
		if (another instanceof Person) {
			Person anotherPerson = (Person) another;
			if (this.getName().equals(anotherPerson.getName()) && this.getAge() == anotherPerson.getAge()) {
				return true;
			} else {
				return false;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		int hash = 17;
		hash = hash * 31 + getName().hashCode();
		hash = hash * 31 + getAge();
		return hash;
	}
}

좋은 웹페이지 즐겨찾기