Language/JAVA

[Java with Unit Test] equals와 hashCode

paran21 2022. 6. 16. 00:35

넥스트스텝에 있는 <자바 플레이그라운드 with TDD, 클린코드>를 시작했는데, 여기서 학습테스트를 소개하고 있다.

https://edu.nextstep.camp/c/9WPRB0ys/

 

플레이그라운드

 

edu.nextstep.camp

익숙하지 않은 API를 공부할 때 단위테스트를 작성하면 해당 API의 사용법도 알 수 있고, 단위테스트에도 익숙해질 수 있다.

코스 시작 부분에서 예제로 String의 몇몇 메서드들을 Junit과 AssertJ를 사용해 단위테스트를 작성하는 연습을 할 수 있다.

 

단위테스트를 통해 어떤 값이 들어가고, 그 결과가 어떻게 출력되는지 바로 알 수 있어서 좋다.

 

그래서 Java 공부를 할 겸 프로젝트를 하나 만들었다.

 

Object

모든 클래스의 최고 조상이기 때문에 모든 클래스에서 바로 사용이 가능하다.

 

equals(Object obj)

  • 참조변수의 값을 통해 두 객체의 값이 같은지 판단한다.
  • 객체를 생성할 때, 메모리의 비어있는 공간을 찾아 생성하므로 서로 다른 두 객체를 equals로 비교하면 항상 false가 나온다.
  • String, Date, File, wrapper클래스 등에서는 주소값이 아닌 내용을 비교하도록 오버라이딩되어 있다.

 

hashCode()

  • 찾고자 하는 값을 입력하면, 그 값이 저장된 위치를 알려주는 해시코드(hashcode)를 반환한다.
  • 객체의 주소값으로 해시코드를 만들어 반환하기 때문에 32 bit JVM에서는 서로 다른 두 객체는 결코 같은 해시코드를 가질 수 없고,
  • 64 bit JVM에서는 8byte 주소값으로 4byte의 해시코드를 만들기 때문에 해시코드가 중복될 수 있다.
  • 앞에서처럼 변수의 값으로 객체의 같고 다름을 판단하기 위해서는 hashCode도 오버라이딩이 필요하며, String에서는 문자열의 내용이 같으면 동일한 해시코드를 반환하도록 오버라이딩이 되어 있다.

 

단위테스트

테스트를 위해 먼저 Value 클래스를 만들었다.

public class Value {
    int value;

    public Value(int value) {
        this.value = value;
    }

}

Object 클래스의 equals와 hashCode를 통해 두 객체를 비교하면 항상 다르게 나온다.

hashCode는 항상 다른 값이 나오도록 System.identityHashCode(Object x)를 사용하였다.

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;


public class ObjectTest {

    private Value v1;
    private Value v2;

    @BeforeEach
    void setUp() {
        v1 = new Value(10);
        v2 = new Value(10);
    }

    @Test
    void equalsTest() {
        Assertions.assertThat(v1.equals(v2)).isEqualTo(false);
    }

    @Test
    void hashCodeTest() {
        Assertions.assertThat(System.identityHashCode(v1)).isNotEqualTo(System.identityHashCode(v2));
    }
}

 

 

반면에 String의 equals와 hashCode는 내용을 비교하여 문자열이 일치하면 true를 리턴한다.

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class StringTest {

    private String str1;
    private String str2;

    @BeforeEach
    void setUp() {
        str1 = "abc";
        str2 = "abc";
    }

    @Test
    void equalsTest() {
        Assertions.assertThat(str1.equals(str2)).isEqualTo(true);
    }

    @Test
    void hashCodeTest() {
        Assertions.assertThat(str1.hashCode()).isEqualTo(str2.hashCode());
    }
}

 

 

 

참고자료: 자바의 정석