Java에서는 primitive type(기본 데이터 타입)이 같은지 비교할 때, == 연산자를 사용한다. 이 때문에 Java에서 문자열을 처음 비교하는 몇몇 사람들은 객체를 == 연산자로 비교하고 false를 반환받는다. 이 포스팅에서는 == 연산자부터 Object class의 equals & hashCode 까지의 내용을 다룬다.
== 연산자== 연산자는 동일함을 뜻한다. 예로, a == b 라고 한다면 a는 b와 동일하다는 뜻이다.
그렇다면 어떤 기준으로 동일성을 판단할까?
이는 primitive type인지 reference type인지에 따라 다르다. Java의 메모리 영역은 static, stack, heap 영역으로 나뉜다. 이 중 stack 영역에 데이터에 대한 정보가 저장된다.
== 연산자로 비교하면 실제 값이 비교되며 동일성을 판단하게 된다.int a = 1;
int b = 1;
int c = 2;
System.out.println(a == b);
System.out.println(a == c);
// 결과
true
false== 연산자로 비교하게 된다면 실제 데이터값이 아닌 참조 값을 비교하게 되는 것이다.class Money {
long amount;
Money(long amount) {
this.amount = amount;
}
}Money a = new Money(1000);
Money b = new Money(1000);
Money c = new Money(5000);
System.out.println(a == b);
System.out.println(a == c);
// 결과
false
falseequals 를 이용할 수 있다.equals 메서드아래 코드는 Object class의 equals 메서드의 코드이다.
/**
* Indicates whether some other object is "equal to" this one.
* <p>
* The {@code equals} method implements an equivalence relation
* on non-null object references:
* ...생략
**/
public boolean equals(Object obj) {
return (this == obj);
}
equals() 메서드의 comment를 보면 “equivalence relation을 구현한다”라고 적혀있다. 즉, equals는 동등성을 구현한다는 것이고, 우리는 이 메서드를 재정의하여 비교 대상이 논리적으로 같은 데이터 값을 가졌는지를 비교할 수 있다는 것이다. equals는 아래와 같이 재정의해 볼 수 있다.
class Money {
long amount;
Money(long amount) {
this.amount = amount;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Money money = (Money) o;
return amount == money.amount;
}
@Override
public int hashCode() {
return Objects.hash(amount);
}
}
그런데 구현된 코드에 다루지 않은 내용인 hashCode()가 재정의 되어 있다. 사실 Object class의 equals 메서드의 comment에는 아래와 같이 자바 규칙에 대한 내용이 포함되어 있다.
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
즉, 일반적으로 equals 메서드를 재정의하면 hashCode 메서드도 재정의해야 한다는 것이다. 더 자세히 알아보자.
hashCode 메서드먼저, hash라는 단어부터 알아봐야 한다. 간단히 말하자면,
hash는 입력된 데이터를 고정된 길이의 데이터로 반환하는 값을 뜻한다. hash function이라 하고, hash function에서 hash를 반환하여 hash table에 저장하는 과정을 hashing이라고 한다.hash table은 키와 값을 저장하는 데이터 구조를 말한다.hash는 저장, 읽기 작업에 사용되고, 검색 속도가 빠르다는 장점이 있다.
(주의 🙏🏻) hashCode ≠ 주소값 → hashCode는 주소값이 아니다!
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link java.lang.Object#equals(java.lang.Object)}
* method, then calling the {@code hashCode} method on each of the
* two objects must produce distinct integer results. However, the
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
* </ul>
* <p>
* As much as is reasonably practical, the hashCode method defined
* by class {@code Object} does return distinct integers for
* distinct objects. (The hashCode may or may not be implemented
* as some function of an object's memory address at some point
* in time.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
@HotSpotIntrinsicCandidate
public native int hashCode();
Object class의 hashCode()의 코드를 보면, 중요 내용을 아래와 같이 정리할 수 있다.
equals의 내용과 hashCode의 내용을 합해 equals와 hashCode의 관계를 아래와 같이 정리해 보았다.
o1.hashCode() == o2.hashCode() 가 성립해야 한다.o1.equals(o2) 가 성립될 필요는 없다.equals 메서드의 비교 대상을 기준으로 hashCode를 일관성있게 반환해야 한다.== 연산자는 동일성, equals 메서드는 동등성을 다룬다.