equals() , hashCode()

DeadWhale·2022년 12월 16일
0

JAVA

목록 보기
1/10

equals()와 hashCode()의 차이점

❕ **Q. 자바에서 equals()와 hashCode()의 차이점은 무엇일까요? 이 메소드들이 자바의 해시 컬렉션의 성능에 어떤 영향을 끼칠까요?**

“ == ” 는 객체의 주소값을 비교한다.

❕ 객체간 비교가 아닌 `Primitive` 기본자료형 8종이 == 으로 바로 비교되는 이유는 기본 자료형은 객체의 주소를 저장하는 것이 아닌 값 자체를 참조하기 때문이다.
int i = 1;
String s = new String("a");

i ⇒ 1
s ⇒ vo.HashCode_Vo@5b46881

“ equals ” 는 객체가 같은 값인지를 비교한다.

❕ String , 컬렉션 외 거의 모든 라이브러리에서 구현되어 있다.
String s1 = new String("a");
String s2 = new String("a");
s1 != s2

s1 과 s2는 각각 별개의 객체로 생성되어 주소값이 다르기 때문에 == 비교가 불가능하다.

하지만

String s1 = "a"
String s2 = "a"
s1 == s2

이렇게 객체를 생성하는 경우 객체를 생성 시 JAVA 내부에서 같은 값이 있는지 확인 후

동일한 주소를 참조하게 만든다 그러니 같은 주소값을 비교하는 형태라 True가 나오게 된다.

“ hashCode ” 는 객체의 값에서 해시 알고리즘을 통해 해시 코드를 생성한다

System.out.println("객체를 == 비교 " +(s1 == s2));
System.out.println("객체를 equals 비교 " +(s1.equals(s2)));
  • 객체를 == 비교 false
  • 객체를 equals 비교 false

현재 For_Equals_And_HashCode_Vo 객체 내부에 equals 가 오버라이딩 안되어있어 생기는 문제.

equals 오버라이딩

@Override
public boolean equals(Object o) {
  if (this == o) return true;
  if (o == null || getClass() != o.getClass()) return false;
  For_Equals_And_HashCode_Vo that = (For_Equals_And_HashCode_Vo) o;
return 
	Objects.equals(str1, that.str1) 
	&& Objects.equals(str2, that.str2) 
	&& Objects.equals(str3, that.str3);
}
  • 만약 현재 객체와 비교대상 객체의 주소값이 같으면 True 반환
  • 대상 객체가 Null 혹은 현재 클래스와 같은 클래스가 아닐때 False를 반환한다.
  • 아닐 경우 비교대상 객체를 현재 객체 자료형으로 형변환 후
    해당 객체 안 요소를 Object.equals( t1,t2) 으로 비교한다

hashCode() 오버라이딩

@Override
public int hashCode() {
  return Objects.hash(str1, str2, str3);
}
  • Objects에 선언된 메서드 중 여러 인자를 받을 수 있도록 오버로딩된 메서드를 호출한다.
  • 자료형 … 매개변수명 ⇒ “ … ”이 Arrays으로 받을수 있도록 도와준다
-- Objects . class
public static int hash(Object... values) {
        return Arrays.hashCode(values);
}
-- Arrays . class
public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}
  • 오브젝트 배열이 null일때 0 반환 객체가 없다는 의미

  • 배열을 반복하며

    • null이 아닐때.
    • 31 * 1 + ( Object.hash() ) ;
  • 최종적으로 Object.class 안에 hashCode 를 호출한다.

  @HotSpotIntrinsicCandidate
  public native int hashCode();
  • 이 부분을 더 찾아봐야겟다.

❕ `private final byte coder;`
  • Javadoc
  • 값의 바이트를 인코딩하는 데 사용되는 인코딩의 식별자
  • 이 구현에서 지원되는 값은 LATIN1 UTF16입니다.
  • byte의 크기는 1byte(8bit) , -128 ~ 127

  • coder를 비교
static final boolean COMPACT_STRINGS;

byte coder() {    
    return COMPACT_STRINGS ? coder : UTF16;
}

COMPACT_STRINGS 가 false일 때는 UTF16으로 인코딩 된다

❕ Objects . class
  • JavaDoc

이 클래스는 객체에서 작동하거나 작동하기 전에

특정 조건을 확인하기 위한 정적 유틸리티 메서드로 구성됩니다.

이러한 유틸리티에는

개체의 해시 코드를 계산하고,

개체에 대한 문자열을 반환하고,

두 개체를 비교하고,

인덱스 또는 하위 범위 값이 범위를 벗어났는지 확인하는

널 세이프 또는 널 허용 방법이 포함됩니다.

  • 기본 생성자를 private으로 구현해 막아놨다

.equals( Object a )

❕ Objects.equals(Object a )
  • JavaDoc
    • 기본적으로 Object 클래스 안에서 선언되어 있는 방식
    • 두 값의 메모리 주소가 있는지만 비교
    • 내가 구현한 객체에서 오버라이딩해 사용할 수 있다.

  • Java.lang.String에서 오버라이딩된 .equals()

!

  • 기본과 동일하게 메모리 주소가 같을 경우 True 반환
  • 객체가 스트링일때 문자열로 형변환 수행
  • coder()을 통해 문자열의 인코딩을 확인한다
  • isLatin1() 메서드를 호출한다
    • LATN1 == @Native static final byte LATIN1 = 0;
    • COMPACT_STRINGS 와 coder 가 모두 0 이라면 true 반환
private boolean isLatin1() {
        return COMPACT_STRINGS && coder == LATIN1;
    }
  • UTF16.equals가 호출되게 되면
@HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            int len = value.length >> 1;
            for (int i = 0; i < len; i++) {
                if (getChar(value, i) != getChar(other, i)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
  • StringUTF16 클래스의 equals가 호출된다.
  • 인자의 길이가 같으면 바이트코드를 비교하며 반복한다.
  • 최종적으로 바이트코드를 반복하며 값을 비교한!!

.equals( Object a , Object b )

❕ Objects.equals(Object a , Object b)
  • JavaDoc
    • 인수가 서로 같으면 true를 반환하고 그렇지 않으면 false를 반환합니다.
    • 따라서 두 인수가 모두 null이면 true가 반환되고
    • 정확히 하나의 인수가 null이면 false가 반환됩니다.
    • 그렇지 않으면 첫 번째 인수의 등식 방법을 사용하여 동일성을 결정합니다.

  • 두 매개변수의 메모리 주소가 같으면 True 반환
  • 1번 매개변수가 null이 아니면 객체의 오버라이딩된 .equals(2번 매개변수) 를 비교한다

equals 오버라이딩

.hashCode(Object o1);

❕ Objects.hashCode()
  • JavaDoc
    - Null이 아닌 인수의 해시 코드를 반환하고 Null 인수의 경우 0을 반환합니다.
  • null일 경우에는 해시코드를 0으로 반환한다.
  • 해당 객체에서 오버라이딩된 hashCode() 를 호출해 해시 코드를 생성하고 반환한다

글을 나눠 쓰는 연습을 좀 해봐야겟다

고기 뭉탱이같이 여기저기 글을 퍼트려 작성한 느낌….

결론 HashCode는 객체의 메모리주소를 기준으로 생성되며 해시테이블에 저장할 때 주로 사용된다.

해시 알고리즘을 통해 생성되고 해시로 접근하게 되면 O(n)의 시간 복잡도가 걸리게 된다.

해시코드는 프로그램이 실행되는 도중에는 항상 같은 해시코드를 보장한다

.hashCode() 는 탐색을 위해 사용된다.

.equlas() 는 객체 클래스에서 오버라이드에 필요에 맞게 값에 대한 검증을 할 수 있다

String 객체에서 비교하는 것처럼 객체의 메모리 주소값을 비교하다 답 없으면 바이트 코드까지 보내서 검증해버린다.

0개의 댓글