동일성은 두 객체의 메모리 주소가 같음을 의미한다. == 연산자를 통해 판별하며 두 객체가 완전히 같은 경우를 의미한다.
동등성은 두 객체의 값이 같음을 의미한다. equals() 메소드를 통해 변수가 참조하고 있는 객체의 주소가 다르더라도 내용만 같으면 동등하다고 한다.
void 동일성() {
List<String> list1 = List.of("a", "b", "c");
List<String> list2 = list1;
System.out.println(list1 == list2); // true
System.out.println(list1.equals(list2)); // true
}
void 동등성() {
List<String> list1 = List.of("a", "b", "c");
List<String> list2 = List.of("a", "b", "c");
System.out.println(crews1 == crews2); // false
System.out.println(crews1.equals(crews2)); // true
}
동일성() 에서는 list2가 list1을 대입받았기 때문에 메모리 상에서 같은 주소를 가지고 있고, == 비교에서 true를 리턴한다.
동등성() 에서는 list1과 list2 모두 새로운 리스트를 선언했기 때문에 메모리 상 다른 주소를 가지고 있고, == 비교에서는 false를 리턴한다.
동일성이 지켜진다면 동등성은 자연스럽게 지켜지지만, 동등성이 지켜진다해서 동일성이 보장되지는 않는다.
동등성은 equals() 메소드를 통해 판별한다. 하지만 equals() 메소드를 오버라이딩 하지 않고 사용했을 때는 == 과 동일하게 사용된다.
class Car {
private final String name;
public Car(String name) {
this.name = name;
}
}
void 동등성_테스트() {
Car car1 = new Car("제네시스");
Car car2 = new Car("제네시스");
System.out.println(car1.equals(car2)); // false, new로 새로운 객체를 생성했기 때문에 주소값이 다르다.
}
Object 클래스의 equals 메소드는 메모리 내 주소값이 같은지 비교하기 때문에 동등성을 위해 오버라이딩해 사용해야한다.
public boolean equals(Object obj) {
return (this == obj);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Car car = (Car)o;
return name.equals(car.name);
}
객체의 동등성 기준을 재정의 함으로써, 같은 name을 가진 인스턴스를 같은 객체로 인식되게 구현했다. 그러나 만약 HashMap, HashSet등을 사용했을 때는 해쉬값을 비교해 동등성을 비교하므로 hashCode()를 오버라이딩 해야한다.
Set<Car> cars = new HashSet<>();
cars.add(new Car("a"));
cars.add(new Car("a"));
System.out.println(crews.size()); // 2, 해쉬값으로 비교하기 때문에 생각과는 다르게 중복제거가 되지 않음
@Override
public int hashCode() {
return Objects.hash(name);
}