1. toString()
toString() 메서드는 기본적으로 객체의 정보를 문자열로 반환하는 메서드입니다.
기본적으로 Object 클래스에서 제공하는 toString()의 구현은 다음과 같습니다.
클래스 이름 + "@" + 객체의 해시코드(16진수) 형태의 문자열을 반환합니다.
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
2. toString() 기본 사용 예시
class Car {}
public class Main {
public static void main(String[] args) {
Car car = new Car();
System.out.println(car.toString());
System.out.println(car); // println 내부에서 toString() 자동 호출
}
}
/*
Car@6d06d69c
Car@6d06d69c
*/
3. toString()을 오버라이드하여 의미 있는 값 반환
class Car {
String name;
int number;
Car(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public String toString() {
return "name: " + name + ", number: " + number;
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car("Sonata", 1234);
System.out.println(car); // toString() 자동 호출
}
}
/*
name: Sonata, number: 1234
*/
4. equals()
Object 클래스에서 기본적으로 제공하는 equals() 메서드는 두 객체의 참조(주소)를 비교합니다.
즉, 기본적으로 == 연산자와 동일한 동작을 합니다.
5. 기본 equals() 동작 확인
class Car {
String name;
int number;
Car(String name, int number) {
this.name = name;
this.number = number;
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car("Sonata", 1234);
Car car2 = new Car("Sonata", 1234);
Car car3 = car1;
System.out.println(car1.equals(car2)); // false (기본 equals는 참조 비교)
System.out.println(car1.equals(car3)); // true (같은 객체를 참조)
}
}
/*
false
true
*/
6. equals() 오버라이드하여 원하는 기준으로 비교
class Car {
String name;
int number;
Car(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 같은 객체이면 true
if (obj == null || getClass() != obj.getClass()) return false; // 클래스 다르면 false
Car car = (Car) obj; // 형 변환 후 비교
return number == car.number && name.equals(car.name);
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car("Sonata", 1234);
Car car2 = new Car("Sonata", 1234);
Car car3 = new Car("Avante", 5678);
System.out.println(car1.equals(car2)); // true (name과 number가 같음)
System.out.println(car1.equals(car3)); // false (값이 다름)
}
}
/*
true
false
*/
7. equals() 오버라이드할 때 주의할 점
- this == obj 먼저 비교 : 같은 객체라면 바로 true 반환.
- obj == null 체크 : null.equals(객체) 호출 시 예외 방지.
- getClass()로 클래스 비교 : 다른 클래스라면 false 반환.
- 형 변환 후 비교 : instanceof 대신 getClass()를 사용하면 정확한 타입 체크 가능.
- 모든 중요한 필드 비교 : 객체가 같다고 판단할 기준을 정해야 함.
8. hashCode()와의 관계
- equals()를 오버라이드하면 반드시 hashCode()도 함계 오버라이드해야 합니다.
- 이유 : equals()가 같다고 판단한 두 객체는 같은 hashCode() 값을 가져야 합니다.
- 그렇지 않으면 HashMap, HashSet 같은 컬렉션에서 정상적으로 동작하지 않습니다.
9. hashCode()
기본적으로 Object 클래스에서 제공하는 hashCode()는 객체의 메모리 주소를 기반으로 해시 값을 반환합니다.
즉, 기본적으로 각각의 객체는 서로 다른 해시코드를 가집니다.
10. 기본 hashCode() 동작 확인
class Car {
String name;
int number;
Car(String name, int number) {
this.name = name;
this.number = number;
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car("Sonata", 1234);
Car car2 = new Car("Sonata", 1234);
System.out.println(car1.hashCode()); // 해시코드 값
System.out.println(car2.hashCode()); // car1과 다름 (기본적으로 다른 객체이므로)
}
}
/*
1163157884
1956725890
*/
11. hashCode() 오버라디으하여 값이 같으면 동일한 해시코드 반환
import java.util.Objects;
class Car {
String name;
int number;
Car(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Car car = (Car) obj;
return number == car.number && name.equals(car.name);
}
@Override
public int hashCode() {
return Objects.hash(name, number);
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car("Sonata", 1234);
Car car2 = new Car("Sonata", 1234);
System.out.println(car1.equals(car2)); // true (값 비교)
System.out.println(car1.hashCode()); // car1과 car2의 해시코드가 같음
System.out.println(car2.hashCode());
}
}
/*
true
356573597
356573597
*/
12. hashCode() 구현 방법
@Override
public int hashCode() {
return Objects.hash(name, number);
}
- 직접 해시코드 계산
- 31은 소수(prime number)로, 해시 충돌을 줄이는 데 도움을 줍니다.
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + number;
return result;
}
13. equals()와 hashCode()의 관계
- equals()가 true라면 hashCode() 값도 같아야 한다.
- hashCode()가 같다고 해서 equals()가 true라는 보장은 없다.
- 서로 다른 객체가 우현히 같은 해시코드를 가질 수도 있음(해시 충돌).
@Override
public boolean equals(Object obj) {
return true; // 항상 true를 반환하는 잘못된 equals()
}
@Override
public int hashCode() {
return 1234; // 모든 객체의 해시코드를 같은 값으로 반환
}
14. hashCode()가 중요한 이유
컬렉션 |
hashCode()의 역할 |
HashSet |
중복 요소 검사 시 사용 |
HashMap |
키의 해시코드를 이용해 빠르게 검색 |
HashTable |
키의 해시코드를 이용해 데이터 저장 |
import java.util.HashSet;
import java.util.Objects;
class Car {
String name;
int number;
Car(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Car car = (Car) obj;
return number == car.number && name.equals(car.name);
}
@Override
public int hashCode() {
return Objects.hash(name, number);
}
}
public class Main {
public static void main(String[] args) {
HashSet<Car> cars = new HashSet<>();
cars.add(new Car("Sonata", 1234));
cars.add(new Car("Sonata", 1234)); // 중복 요소 추가
System.out.println(cars.size()); // 1 (중복이 제거됨)
}
}
/*
1
*/