이 글은 유튜브 '자바의 정석 - 기초편'을 보고 정리한 글입니다.
📂content
1. hashCode()
- 객체의 해시코드(hash code)를 반환하는 메서드
- Object클래스의 hashCode()는 객체의 주소를 int로 변환해서 반환
public class Object {
...
public native int hashCode();
native는 native method라는 것이다. 이 말은 os가 가지고 있는 메서드라는 것. 주로 c언어로 작성되어 있다.
그래서 이것을 사용하면 실제로는 c언어로 작성되었지만 마치 java로 작성된 메소드처럼 사용할 수 있다.
해시코드는 객체의 지문이다.
- equals()를 오버라이딩하면, hashCode()도 오버라이딩해야 한다.
why?
이 둘은 객체의 주소를 가지고 작업을 한다는 공통점이 있다.
그래서 만약에 equals()를 iv(Instance Variables : 인스턴스 변수)를 가지고 객체가 같은지 아닌지를 판단하도록 오버라이딩한다면, hashCode()도 iv를 이용해서 작업하도록 오버라이딩해야한다. 그 이유는 equals()의 결과가 true인 두 객체의 해시코드는 같아야 하기 때문이다.
만약에 hashCode()를 오버라이딩하지 않으면, hash 값을 사용하는 Collection Framework(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생된다.
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1.equals(str2)); //true
System.out.println(str1.hashCode()); //96354
System.out.println(str2.hashCode()); //96354
- System.identityHashCode(Object obj)는 Object클래스의 hashCode()와 동일
System.out.println(System.identityHashCode(str1); //3526198
System.out.println(System.identityHashCode(str2); //7699183
32bit JVM에서는 주소범위가 int이다.
그런데 64bit JVM에서는 주소가 8byte이다. 즉 long이다. 그래서 이걸 가지고 해시코드를 만들면 겹칠 수도 있다.
왜냐하면 메서드가 int이기 때문이다. 원래는 long으로 바뀌어야 하는데 너무 많이 쓰이는 메서드이기 때문에 함부로 바꿀 수가 없다.
2. toString(), toString()의 오버라이딩
- toString() : 객체를 문자열(String)으로 변환하기 위한 메서드
public String toString() { //Object클래스의 toString()
//설계도객체.클래스이름+"@"+16진수 객체 주소
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
⍟실습
toString(), equals(), hashCode() 오버라이딩
class Card {
String kind;
int number;
Card() {
this("SPADE", 1);
}
Card(String kind, int number) {
this.kind = kind;
this.number = number;
}
}
class Ex9_4 {
public static void main(String[] args) {
Card c1 = new Card();
Card c2 = new Card();
System.out.println(c1.toString()); // Card@19e0bfd
System.out.println(c2.toString()); // Card@139a55
}
}
그런데 Object에 있는 toString()는 객체의 주소값만 나와서 유용하지 않다. 그래서 오버라이딩을 한다.
1️⃣ toString() 오버라이딩
public String toString() {//toString() 오버라이딩
return "kind : " + kind + ", number : " + number;
}
그러면 결과값이
kind : SPADE, number : 1
kind : HEART, number : 10
와 같이 Instance Variables로 나온다. 이것들을 출력하는 이유는 객체는 iv의 집합이기 때문이다.
그래서 객체를 문자열로 변환한다는 것은 iv의 값을 문자열로 변환한다는 것과 같다.
반드시 이렇게 하는 것은 아니지만 이것이 일반적이다.
2️⃣ equals() 오버라이딩
public boolean equals(Object obj) {
//오버라이딩은 선언부가 일치해야하기 때문에 Object를 써야 한다.
//toString()은 Ojbect에 있는 메소드
if(!(obj instanceof Card))
return false;
Card c = (Card)obj;
return this.kind.equals(c.kind) && this.number == c.number;
}
/* 기존 equals() 코드
즉, 주소값을 비교한다.
public boolean equals(Object obj) {
return this == obj;
}
*/
3️⃣ hashCode() 오버라이딩
public int hashCode() {
//Objects클래스는 객체와 관련된 유용한 메서드를 제공하는 유틸 클래스
//iv를 가지고 판단
return Objects.hash(kind, number);
}
- `int hash(Object ... values) {...}`
매개변수가 가변인자(Object...)라서 호출시 지정하는 값의 개수가 정해져있지 않다.
- hashCode()를 주석처리하면 주소객체값이 다르게 나온다.
❇️정리
1. equals() 오버라이딩시 hashCode()도 무조건 오버라이딩
why?
hashCode()를 오버라이딩 안 하면, equals()가 true로 나오는데 객체의 주소값은 다른 이상한 경우가 발생
그렇게 되면 hash값을 사용하는 CollectionFramework를 사용할 때 이상한 결과가 나온다.
2. 오버라이딩은 InstanceVariable을 이용해서 같은지 여부를 판단
출처
'🎥Back > 자바의 정석' 카테고리의 다른 글
[JAVA의 정석]스레드 (0) | 2024.02.29 |
---|---|
[JAVA의 정석]Object클래스와 equals() (0) | 2024.02.29 |
[JAVA의 정석]사용자 정의 예외 만들기, 예외 되던지기 (0) | 2024.02.28 |
[JAVA의 정석]예외발생시키기 (0) | 2024.02.28 |
[JAVA의 정석] 프로그램오류. try-catch (0) | 2024.02.18 |