자바의 모든 클래스는 Object 클래스를 상속받습니다.
그리고 Object클래스에는 equals() 와 hashCode() 라는 메소드가 선언되어 있습니다.
이 메소드들은 각각 어떤 역할일까요? 이 둘의 차이점은 무엇일까요?
equals()와 hashCode() 메서드는 객체 지향 프로그래밍에서 중요한 메서드로, 객체 간의 동일성과 동등성을 다루는 데 사용됩니다.
들어가기 전에
동일성은 Identity = 메모리 내 주소값이 같은지 비교합니다.
동등성은 Equality = 논리적 지위가 동등한지 비교합니다.
예를들어, 애플 아이폰이 2대있다. 두 휴대폰은 기종도 같고 동일한 색상 동일한 스펙을 가지고 있다. 이 두 개의 휴대폰은 동일한가?
답은 아니다. 휴대폰은 각 기기마다 고유 주소가 있고 아이폰은 MAC 주소가 존재한다. 즉, 동일한 스펙이지만 엄연히 두 기기는 각자 유니크한 특성을 갖고 있다고 할 수 있다. (= 동일하지 않다는 것)
이번에는 그럼 동등한가? 답은 그렇다. 사회적으로 동일한 스펙과 심지어는 컬러가 달라도 스펙이 동일한 같은 시리즈의 기기라면 같은 휴대폰이라고 말한다. "이건 아이폰15 블루야", "이건 아이폰15 그린이야" 이렇게 말하지 않잖아요..? 그냥 "응 아이폰 15~", "응 아이폰 15프로~" 이정도로만 구분한다. 바로 그 이유는 사회적으로 두 기계는 논리적 지위가 동등하기 때문이다.
꼭 알고가기
일단 동등성에 먼저 주목해보면, 동등성을 판단하기 위해 스펙이 같다는 논리적 기준이 있다. 논리적 기준은 절대적 기준과는 조금 다르다. 다시말하면 논리적 기준은 개발자가 언제든 정할 수 있다는 것이다😱
논리적 기준을 개발자가 만들 필요가 있나?
개발을 하면서 메모리 내 주소값이 다른, 별개의 객체라 할지라도, 특정 조건을 만족하면 논리적으로 같은 객체로 다뤄야하는 경우가 있거든요..그리고 그 특정 조건은, 매번 달라질 수 있어야 한답니다 ◠‿◠ ...
바로 이런 이유들 때문에 개발자는 객체를 다룰 때 "자, 지금부터 이 두개가 같은거야!"라는 논리적 기준을 정하고, 그 기준을 적용해야 한다. 여기서 필요한 개념이 equals()오버라이딩이다.
그런데 equals()만 오버라이딩해서 나만의 기준을 정해주면 될까?
아까 위에 동일성을 판단하려면 메모리 내의 주소 값이 같은지 비교한다고 했다.. 논리적 기준은 어찌한다해도 메모리는 어쩌냐..(?)여기서 바로 그걸 해결할 수 있는 것이 hashCode() 오버라이딩이다. 아얘 hash까지 동일한 것으로 취급될 수 있게 해주면 완.전.범.죄.😎
따라서 두 개의 메서드는 항상 붙어다니면서 완전 범죄를 하게 된다ㅎㅎ
[+ 11.01 추가] 동일성을 갖게 해주기 위해 hashCode() 오버라이딩 하는건가요?
동일하다는 의미를 주기위해 hashCode()를 오버라이딩한다고 이해하는 것은 적절한 방향이 아닙니다😱그 둘은,, 적합한 비교대상이 아니에요...! 어떤 문제가 생기는지 설명해보겠습니다.
hash 값을 사용하는 Collection(HashMap, HashSet, HashTable)에서 문제가 생기는데요. 객체가 논리적으로 같은지 equals 비교할 때 절차를 살펴보면
1. HashCode()리턴값을 확인
1-1. 같을경우, equals() 리턴값을 확인
1-2. 다를경우, 다른객체로 처리
2. equals()의 리턴값을 확인
2-1. 같을경우, 동등한 객체로 처리
2-2. 다를경우, 다른객체로 처리
이렇게 처리됩니다! 따라서 hashCode만 동일한 것은 다른 객체로 판단되지 않습니다☺️(완전범죄에 실패한거죠ㅠㅠ)
객체의 중복을 허용하지 않는 HashSet에 동일한 이름의 객체를 add하고 hashCode()만 오버라이딩을 한 후 set의 결과를 살펴보면 두 개가 add 됩니다! 코드를 볼까요?
public class User{
private final String name;
public User(String name){
this.name = name;
}
@Override
public int hashCode(){
//이름으로 해싱합니다.
return Objects.hashCode(name)
}
public static void main(String[] args){
Set<User> set = new HashSet<>();
User user1 = new User("judy");
User user2 = new User("pobi");
//두명의 사람을 user set에 추가
set.add(user1);
set.add(user2);
// 중복없이 데이터들을 담은 결과는?
System.out.println(set.size());
}
}
2
두 개의 해시값이 서로 달라서 들어간게 아닐까?
(주디 특,, override가 제대로 안된 것을 의심함. 절대 본인이 잘못이라고 생각못함 ◠‿◠ ) 코드로 확인해볼까요?
public class User{
private final String name;
public User(String name){
this.name = name;
}
@Override
public int hashCode(){
//이름으로 해싱합니다.
return Objects.hashCode(name)
}
public static void main(String[] args){
Set<User> set = new HashSet<>();
User user1 = new User("judy");
User user2 = new User("pobi");
//두명의 사람을 user set에 추가
set.add(user1);
set.add(user2);
System.out.println(user1.hashCode());
System.out.println(user2.hashCode());
}
}
99162322
99162322
결과적으로 hashCode()는 같으나 두 객체는 동등성을 인정하지 않았기 때문에 동등한 것으로 취급하지 않은 것입니다.
무조건 재정의를 해야하냐 ‘나는Collection을 안쓸거라면???’
무조건 재정의해야한다고 말할 수 없지만 통상적으로 같이 재정의하기 때문에 습관을 가져가는 것이 좋다고 생각합니다. 객체에 대한 일관성을 유지하는 측면에서도 재정의하는 것이 좋습니다.
equals() 메서드
가장 많이 사용하는 equals() 메서드는 동등성(equivalence) 비교에 사용됩니다. 이 메서드는 두 객체가 동등한지(=내용이 같은지)를 비교합니다. 자바의 equals() 메서드는 Object 클래스에 정의되어 있고, 모든 자바 클래스는 Object 클래스를 상속받으므로 이 메서드를 오버라이드(재정의)할 수 있습니다.
기본 구현은 객체의 레퍼런스(메모리 위치)가 같은지를 비교합니다. 즉, 객체의 실제 내용을 비교하는 것이 아니라, 객체가 동일한 인스턴스인지를 확인합니다. 필요하다면, 클래스마다 이 메서드를 오버라이드하여 두 객체가 동등한지를 비교하도록 구현할 수 있습니다.
hashCode() 메서드
HashCode() 메서드는 해시 코드 생성에 사용됩니다. 이 메서드는 객체를 해시맵과 같은 해시 기반 자료 구조에서 사용하기 위한 해시 코드를 생성합니다. hashCode() 메서드의 기본 구현은 객체의 메모리 위치에 기반한 해시 코드를 반환합니다. 이는 객체가 다르면 다른 해시 코드를 반환하므로, 객체를 해시맵에 저장할 때 다른 객체로 취급됩니다.
객체의 hashCode() 메서드를 오버라이드하여 객체 내용에 기반한 고유한 해시 코드를 반환하도록 재정의할 수 있습니다.
equals() 와 hashCode()의 차이
equals() 메서드는 두 객체의 내용이 동일한지를 확인하는 데 사용되며, 동등성(equivalence)을 판단합니다.
hashCode() 메서드는 객체를 해시맵과 같은 해시 기반 자료 구조에서 식별하기 위한 해시 코드를 생성합니다. 객체가 서로 다르면 다른 해시 코드를 반환하며, 같은 객체에 대해서는 항상 같은 해시 코드를 반환해야 합니다.
객체를 해시 기반 자료 구조에 저장하려면 equals()와 hashCode() 메서드를 일관되게 구현해야 합니다.
equals() 메서드는 동등성을 판단하고, hashCode() 메서드로 객체를 식별하는 데 사용합니다.
'Study > cs (computer science)' 카테고리의 다른 글
쿠키 2부 : 세션은 쿠키가 필요하다 (1) | 2023.11.30 |
---|---|
쿠키 1부 : HTTP로 설명하는 쿠키 (5) | 2023.11.24 |
REST API/RESTful API Design Guide/REST 디자인 패턴/Http Methods 는 무엇인가 #2 (0) | 2023.01.04 |
REST API/RESTful API란/Representational State Transfet API/REST 디자인패턴 쓰는 이유 #1 (0) | 2023.01.03 |
빌드(Build)/Jankins 젠킨스/CI도구 써야하는 이유 (0) | 2023.01.03 |