
class Person {
private String name;
private int age;
public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Person p1 = new Person("justin", 10);
Person p2 = new Person("justin", 10);
boolean samePerson = p1.equals(p2); // ?
s1.equals(s2) 는 true일 것 같지만 false이다.
그 이유는 Object 클래스의 equals함수는 단지 == 비교로 두 객체의 메모리 주소를 비교하고 있기 때문이다.
new Person() 명령어를 통해 메모리에 2개의 객체를 생성했고 p1, p2는 각기 다른 주소를 가리키고 있는 것이다.
equals 재정의
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Student))
return false;
Student other = (Student)o;
boolean nameIsEqual = (this.name == null && other.name == null) ||
(this.name != null && this.name.equals(other.name));
return this.age == other.age && nameIsEqual;
}
equals 규약
- 재귀: 객체는 자신과 같아야 한다.
- 대칭: x.equals(y)는 y.equals(x)와 동일한 결과를 반환해야 한다.
- 전이: x.equals(y) 및 y.equals(z)이면 x.equals(z)도 참이여야한다.
- 일관성: equals()에 포함된 속성이 변경되는 경우에만 equals()의 값이 변경되어야 한다.
equals 규약 위반 - equals()를 재정의한 클래스를 상속하는 경우 가장 자주 발생한다.
class Student extends Person {
private String major;
@Override
public boolean equals(Object o) {
if(o == this)
return true;
if(!(o instanceof Student))
return false;
Student other = (Studnet)o;
boolean nameIsEqual = (this.name == null && other.name == null) ||
(this.name != null && this.name.equals(other.name));
boolean majorIsEqual = (this.major == null && other.major == null) ||
(this.major != null && this.major.equals(other.major));
return this.age == this.age && nameIsEqual && majorIsEqual;
}
}
Person p1 = new Person("Amy", 20);
Student s1 = new Student("Amy", 20, "Design");
p1.equals(s1); // true
s1.equals(p1); // false
equals의 대칭 규약 위반이 일어난다.
상속(inheritance)보다는 합성(composition)
class Teacher {
private Person person;
private String major;
Person(String name, int age, String major) {
this.person = new Person(name, age);
this.major = major;
}
@Override
public boolean equals(Object o) {
if(o == this)
return true;
if(!(o instanceof Teacher)
return false;
Teacher other = (Teacher)o;
boolean personIsEqual = (this.person == null && other.person) ||
(this.person != null && this.person.equals(other.person));
boolean majorIsEqual = (this.major == null && other.major) ||
(this.major != null && this.major.equals(other.major));
return personIsEqual && majorIsEqual;
}
}
hashCode() 재정의 이유
hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생한다. 이러한 Collection은 hashCode()를 사용하여 주어진 키에 대한 해시 값을 계산하기 때문이다.
hashCode ()규약
- 내부 일관성: hashCode() 값은 equals() 안에 있는 속성이 변경되는 경우에만 변경될 수 있다. 동일한 객체는 수정되지 않는 한 hashCode()는 일관되게 동일한 값을 반환해야 한다.
- equals()에 따라 두 객체가 같으면 두 객체의 각각 hashCode() 또한 동일한 값이 생성되어야 한다.
- equals()에 따라 두 객체가 같지 않더라도 두 객체의 각각 hashCode()는 같을 수 있다.
class Person {
private String name;
private int age;
public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return age * name.hashCode();
}
}
표준 hashCode() 구현
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + age;
hash = 31 * hash + (name == null ? 0 : name.hashCode());
return hash;
}
Java 7부터는 Objects.hash() 메서드를 제공
Lombok을 사용하여 @EqualsAndHashCode 어노테이션 사용 가능

class Person {
private String name;
private int age;
public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Person p1 = new Person("justin", 10);
Person p2 = new Person("justin", 10);
boolean samePerson = p1.equals(p2); // ?
s1.equals(s2) 는 true일 것 같지만 false이다.
그 이유는 Object 클래스의 equals함수는 단지 == 비교로 두 객체의 메모리 주소를 비교하고 있기 때문이다.
new Person() 명령어를 통해 메모리에 2개의 객체를 생성했고 p1, p2는 각기 다른 주소를 가리키고 있는 것이다.
equals 재정의
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Student))
return false;
Student other = (Student)o;
boolean nameIsEqual = (this.name == null && other.name == null) ||
(this.name != null && this.name.equals(other.name));
return this.age == other.age && nameIsEqual;
}
equals 규약
- 재귀: 객체는 자신과 같아야 한다.
- 대칭: x.equals(y)는 y.equals(x)와 동일한 결과를 반환해야 한다.
- 전이: x.equals(y) 및 y.equals(z)이면 x.equals(z)도 참이여야한다.
- 일관성: equals()에 포함된 속성이 변경되는 경우에만 equals()의 값이 변경되어야 한다.
equals 규약 위반 - equals()를 재정의한 클래스를 상속하는 경우 가장 자주 발생한다.
class Student extends Person {
private String major;
@Override
public boolean equals(Object o) {
if(o == this)
return true;
if(!(o instanceof Student))
return false;
Student other = (Studnet)o;
boolean nameIsEqual = (this.name == null && other.name == null) ||
(this.name != null && this.name.equals(other.name));
boolean majorIsEqual = (this.major == null && other.major == null) ||
(this.major != null && this.major.equals(other.major));
return this.age == this.age && nameIsEqual && majorIsEqual;
}
}
Person p1 = new Person("Amy", 20);
Student s1 = new Student("Amy", 20, "Design");
p1.equals(s1); // true
s1.equals(p1); // false
equals의 대칭 규약 위반이 일어난다.
상속(inheritance)보다는 합성(composition)
class Teacher {
private Person person;
private String major;
Person(String name, int age, String major) {
this.person = new Person(name, age);
this.major = major;
}
@Override
public boolean equals(Object o) {
if(o == this)
return true;
if(!(o instanceof Teacher)
return false;
Teacher other = (Teacher)o;
boolean personIsEqual = (this.person == null && other.person) ||
(this.person != null && this.person.equals(other.person));
boolean majorIsEqual = (this.major == null && other.major) ||
(this.major != null && this.major.equals(other.major));
return personIsEqual && majorIsEqual;
}
}
hashCode() 재정의 이유
hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생한다. 이러한 Collection은 hashCode()를 사용하여 주어진 키에 대한 해시 값을 계산하기 때문이다.
hashCode ()규약
- 내부 일관성: hashCode() 값은 equals() 안에 있는 속성이 변경되는 경우에만 변경될 수 있다. 동일한 객체는 수정되지 않는 한 hashCode()는 일관되게 동일한 값을 반환해야 한다.
- equals()에 따라 두 객체가 같으면 두 객체의 각각 hashCode() 또한 동일한 값이 생성되어야 한다.
- equals()에 따라 두 객체가 같지 않더라도 두 객체의 각각 hashCode()는 같을 수 있다.
class Person {
private String name;
private int age;
public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return age * name.hashCode();
}
}
표준 hashCode() 구현
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + age;
hash = 31 * hash + (name == null ? 0 : name.hashCode());
return hash;
}
Java 7부터는 Objects.hash() 메서드를 제공
Lombok을 사용하여 @EqualsAndHashCode 어노테이션 사용 가능