hashCode(), toString()
ch9-4 hashCode()
- 객체의 해시코드 (hashcode) 를 반환 하는 메서드.
해시코드는 정수값 이다. (해싱 알고리즘)
- Object 클래스의 hashcode() 는 객체의 주소를 int로 변환 해서 반환 한다.
- equals()를 오버라이딩 하면, hashCode()도 오버라이딩 해야 한다.
★ equals()의 결과가 true인 두 객체의 해시코드는 반드시 같아야 한다. (당연한 말)
즉, equals() 메서드를 재정의 해서, 두 객체가 같아서 true를 반환 하면, 두 객체의 해시코드가 반드시 같게 된다.
ch9-5~6 toString(), toString()의 오버라이딩
- toString() : 객체를 문자열 (String) 으로 변환 하기 위한 메서드.
예제 01 )
class Ex9_3 {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1.equals(str2));
System.out.println(str1.hashCode()); // 오버라이딩 되어 있다.
System.out.println(str2.hashCode());
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
// 해시코드는 객체의 주소값을 가지고 만든 정수값 이기 때문에,
// 오버라이딩이 되어 있지 않으면,
// 원래는 str1과 str2 도 다르게 나와야 한다.
// 결과값이 같게 나오는 이유는 이미 오버라이딩이 되어 있기 때문 이다.
// 참고
// identityHashCode()는 Object 클래스의 hashCode() 메서드와 동일 하다.
// 근데 identityHashCode()는 언제 사용하냐면,
// 오버라이딩 하기 전에 기능이 필요 할 때 사용 한다.
[ console ]
String 클래스는 equals() 메서드를 오버라이딩 해두었다.
즉, 문자열 값 비교를 위해 재정의 되어 있다.
String 클래스의 equals() 메서드가 위와 같이 재정의 되어 있기 때문에,
문자열값이 같다면,
결과값은 true가 나오게 될것이고,
따라서, hashcode도 동일 하게 나올것이다.
이때,
identityHashCode() 라는 메서드가 있다는것을 참고하자.
equals() 메서드를 재정의 하지 않았다면,
서로 다른 객체를 equals() 메서드로 같은 비교 하면,
무조건 false를 반환 하게 된다.
그렇다는것은 hashcode도 다르게 나온다는 의미 이다.
[ 참고 ]
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
위와 같이, String 클래스의 equals() 메서드는 이렇게 재정의 되어 있다.
참조값이 같은지 확인해서, 두 문자열 객체가 동일한 객체인지 검사 하고,
전달된 객체가 String 클래스의 인스턴스인지 확인해서,
두 문자열의 길이를 비교해서, 길이가 다르면 false를 반환 하고,
두 문자열의 내용을 각 문자 하나씩 비교해서 모든 문자가 일치하는지 확인 하고,
일치 하지 않으면 false를 반환 하고,
내용이 모두 일치하는 경우에만 true를 반환 한다.
예제 02 )
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.equals(c2));
System.out.println(c1.toString());
System.out.println(c2.toString());
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
}
}
Card 자료형을 인스턴스화한 객체 2개를 볼 수 있고,
이 둘을 그냥 비교하면 당연히 false를 반환 하게 된다.
또한, 객체 자체를 println() 하게 되면 무언가 주소값 느낌의 내용을 출력 하게 된다.
따라서,
equals() 메서드를 재정의 하고,
toString() 메서드도 재정의 하려 한다.
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) { // instanceof 와 유사한 기능.
return false;
}
Card card = (Card) obj;
return number == card.number && Objects.equals(kind, card.kind);
}
위와 같이, equals() 메서드를 재정의 할 수 있다.
위의 코드는 개발자가 직접 작성한게 아니라,
이클립스 등에게 만들어달라하면 위와 같이 자동으로 만들어 주게 된다.
하지만, 길고, 복잡해 보이기 때문에, 직접 만드는것도 나쁘지 않다.
equals() 메서드를 재정의 하면, hashCode() 메서드도 재정의 할 수 있다.
@Override
public int hashCode() {
return Objects.hash(kind, number);
}
// int hash(Object.. values) { .. }
// 매개변수가 가변 인자 (Object ..) 라서,
// 호출시 지정 하는 값의 개수가 정해져 있지 않다.
hashCode() 메서드는 위와 같이 작성 하면 된다.
@Override
public String toString() {
return "Card{" +
"kind='" + kind + '\'' +
", number=" + number +
'}';
}
toString() 은 iv를 가지고 객체를 객체의 iv의 값들로 출력 할 수 있도록 재정의 했다.
[ console ]
[ 참고 ]
기본 toString() 메서드는 아래와 같다.
이것을 다시 확인해보면 아래와 같다.
// getClass()는 Class 이름을 나타낸다고 했고,
// @는 at. 즉, ~의 위치 를 의미 한다.
// hashCode()는 객체의 주소값을 정수값으로 바꾼다고 했고,
// 그 정수값을 toHexString() 메서드의 인자로 넣는다.
// toHexString() 메서드는 16진수의 문자열로 바꿔주는 메서드 이다.
// 반환값이 위와 같기 때문에, 유용 하지 않다.
// 따라서, toString() 메서드를 재정의 해서 사용 한다.
// 객체의 iv값이 출력 될 수 있도록 재정의.
'Java의 정석 > java.lang 패키지 & 유용한 클래스' 카테고리의 다른 글
StringBuffer 클래스의 메서드 (0) | 2023.09.02 |
---|---|
StringBuffer 클래스 (문자열 저장 & 다루기) (0) | 2023.09.01 |
StringJoiner, 문자열과 기본형 변환 (0) | 2023.09.01 |
String 클래스, 문자열 비교, 빈 문자열 (0) | 2023.08.31 |
Object 클래스, equals() 메서드 (0) | 2023.08.30 |