- quals() 메서드 => 두 객체의 내용이 같은지를 비교하는 메서드 (동등성)
- hashCode() 메서드 => 두 객체가 같은 객체인지를 비교하는 메서드 (동일성)
- HashSet, HashMap, Hashtable과 같이 Hash로 시작하는 컬렉션 객체들은
객체의 의미상의 동일성 비교를 위해 hashCode()메서드를 호출하여 비교한다.
그러므로 객체가 같은지 여부를 결정하려면 equals()메서드와 hashCode()메서드를 같이 재정의 해야한다.
hashCode() > Objects.hash(변수1, 변수2...) - hashCode()메서드에서 사용하는 '해싱 알고리즘'은 서로 다른 객체들에 대해 같은
hashCode값을 만들어 낼 수 있다.
객체 ==, equals 로 비교하기
public class EqualsHashcodeTest {
public static void main(String[] args) {
Person p1 = new Person(); // new 생성자도 생성
p1.setNum(1);
p1.setName("홍길동");
Person p2 = new Person();
// p2.setNum(2);
// p2.setName("이순신");
p2.setNum(1);
p2.setName("홍길동");
Person p3 = p1;
System.out.println(p1 == p2); // false (주소값이 다름)
System.out.println(p1 == p3); // true
System.out.println("-------------------------");
System.out.println(p1.equals(p2)); // false
System.out.println(p1.equals(p3)); // true
}
}
class Person{ // extends Object
private int num;
private String name;
// 클래스이름과 같은 메소드 생성자 메서드
// public Person(int num, String name) { // 만들지 않으면 자동으로 생성
// super();
// this.num = num;
// this.name = name;
// }
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
객체에 저장되어있는 값이 같지만 new로 새로운 객체로 생성할 경우 == 로 비교하였을 때
==는 주소값을 비교하기 때문에 주소값이 다르므로 false로 표시된다
( .equals는 Person클래스 내에 없음에도 실행할 수 있는 이유는 extends는 없지만
조상 객체인 Object객체를 상속받았기 때문에 사용할 수 있다)
다만 equals로 표현할 경우에도 값이 같음에도 true가 아닌 false의 결과가 나오는데
상속받고있는 Object에서 equals를 주소값을 비교하고 있다는 것을 할 수 있다.
실질적으로 p1과 p2는 다른 주소값을 가지고 있기 때문에 같은 값을 가지고 있음에도 다르다고 나오는 것이다.
public boolean equals(Object obj) {
return (this == obj); // 참조값 비교
}
String도 주소값만 비교했을 때 다르지만 equals를 사용하면 true값이 나온다
>> 그 이유는 Object 상속 부모의 내용을 변경하기 위해선 메소드를 재정의 (Override)가 되어있기 때문이다
그러므로 Person 내에서도 equals에 대한 재정의가 필요하다
< JVM의 실행 메모리구조 >
Method영역 | Call Stack 영역 | Heap영역 |
클래스정보 static 정보 (main) Person 정보 |
main 메소드 이름과 같은 stack frame생성 (main 메소드가 사용하는 영역) 지역변수나 매개변수 생성 args main stack frame 안에 p1 변수 생성 p1의주소값을 저장 ( 100번지 ) p2의 주소값을 저장 ( 200번지 ) p3는 p1의 주소값 참조 (100번지) (p2생성시에도 생성되었다가 200번지에 매개변수 값을 저장후 삭제) 200번지에 매개변수 값을 저장후 삭제) |
객체 생성 (100번지) Instance 변수 p 1의 각각의 변수들 값을 초기화 저장 주소값을 생성 +메소드 (이후 SetNum과 SetName에서 this의 주솟값을 참조하여 값이 저장) (200번지) Instance 변수 p2의 각각의 변수들 값을 초기화 저장 주소값을 생성 +메소드 (이후 SetNum과 SetName에서 this의 주솟값을 참조하여 값이 저장) |
this | this() |
자기 자신을 가져올 때 | 생성자에서 다른 생성자를 호출할 때 사용 |
equals 재정의
import java.util.HashSet;
public class EqualsHashcodeTest {
public static void main(String[] args) {
Person p1 = new Person(); // new 생성자도 생성
p1.setNum(1);
p1.setName("홍길동");
Person p2 = new Person();
// p2.setNum(2);
// p2.setName("이순신");
p2.setNum(1);
p2.setName("홍길동");
Person p3 = p1;
System.out.println(p1 == p2); // false (주소값이 다름)
System.out.println(p1 == p3); // true
System.out.println("-------------------------");
System.out.println(p1.equals(p2)); // true
System.out.println(p1.equals(p3)); // true
System.out.println("-------------------------");
// Hashcode가 같으면 equals로 비교 2번
// 값이 같으면 같은 것으로 취급하게 하고싶다면 Hashcode를 같게하면된다
HashSet<Person> testSet = new HashSet<Person>();
testSet.add(p1);
testSet.add(p2); // 주소가 다르면 중복취급 X
// testSet.add(p3); // 중복된 값 추가 X
System.out.println("set의 개수 : "+testSet.size()); // set의 개수 : 2
System.out.println("p1 : "+p1.hashCode()); // p1 : 366712642
System.out.println("p2 : "+p2.hashCode()); // p2 : 1829164700
System.out.println("p3 : "+p3.hashCode()); // p3 : 366712642
}
}
class Person{
private int num;
private String name;
// 클래스이름과 같은 메소드 생성자 메서드
// public Person(int num, String name) { // 만들지 않으면 자동으로 생성
// super();
// this.num = num;
// this.name = name;
// }
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// equals 재정의
@Override
public boolean equals(Object obj) {
if(this==obj) return true; //나의 참조값과 obj의 참조값이 같을 때 ( 내용비교 필요X )
if(obj==null) return false;
// 같은 종류의 클래스인지 검사
if(this.getClass()!=obj.getClass()) return false;
// 매개변수의 객체를 현재 객체 유형으로 형변환한다.
Person that = (Person) obj; // 같은 종류 클래스 이므로 형변환 후 저장
// 각 값들이 같은지 검사 종류를 정해서 무엇이 같으면 같을지를 정하기
// 이름과 num이 같은 지 검사
return this.getName().equals(that.getName()) && this.getNum()==that.getNum();
}
}
equals값이 같지만 set에 저장되는 이유는
> 먼저 HashSet에 저장되기전 equals보다 Hashcode가 같은지 파악하기 때문이다.
그래서 중복된 값이 나오지 않게 하려면 hashcode값이 같도록 해야한다
그래서 Person 클래스 내에서 hashCode를 재정의 해줘야한다
hashCode재정의
import java.util.HashSet;
import java.util.Objects;
public class EqualsHashcodeTest {
public static void main(String[] args) {
Person p1 = new Person(); // new 생성자도 생성
p1.setNum(1);
p1.setName("홍길동");
Person p2 = new Person();
// p2.setNum(2);
// p2.setName("이순신");
p2.setNum(1);
p2.setName("홍길동");
Person p3 = p1;
System.out.println(p1 == p2); // false (주소값이 다름)
System.out.println(p1 == p3); // true
System.out.println("-------------------------");
System.out.println(p1.equals(p2)); // true
System.out.println(p1.equals(p3)); // true
System.out.println("-------------------------");
// Hashcode가 같으면 equals로 비교 2번
// 값이 같으면 같은 것으로 취급하게 하고싶다면 Hashcode를 같게하면된다
HashSet<Person> testSet = new HashSet<Person>();
testSet.add(p1);
testSet.add(p2); // 주소가 다르면 중복취급 X
// testSet.add(p3); // 중복된 값 추가 X
System.out.println("set의 개수 : "+testSet.size()); // set의 개수 : 1
System.out.println("p1 : "+p1.hashCode()); // p1 : 54151054
System.out.println("p2 : "+p2.hashCode()); // p2 : 54151054
System.out.println("p3 : "+p3.hashCode()); // p3 : 54151054
}
}
class Person{
private int num;
private String name;
// 클래스이름과 같은 메소드 생성자 메서드
// public Person(int num, String name) { // 만들지 않으면 자동으로 생성
// super();
// this.num = num;
// this.name = name;
// }
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// equals 재정의
@Override
public boolean equals(Object obj) {
if(this==obj) return true; //나의 참조값과 obj의 참조값이 같을 때 ( 내용비교 필요X )
if(obj==null) return false;
// 같은 종류의 클래스인지 검사
if(this.getClass()!=obj.getClass()) return false;
// 매개변수의 객체를 현재 객체 유형으로 형변환한다.
Person that = (Person) obj; // 같은 종류 클래스 이므로 형변환 후 저장
// 각 값들이 같은지 검사 종류를 정해서 무엇이 같으면 같을지를 정하기
// 이름과 num이 같은 지 검사
return this.getName().equals(that.getName()) && this.getNum()==that.getNum();
}
// 같은 값일 경우 hashCode()를 같게 함
@Override
public int hashCode() {
return Objects.hash(num, name); // 2개의 값을 이용해 hashcode를 생성하기 때문에 같은 값이면 같은 값이 됨
}
}
'JAVA > HIGH JAVA' 카테고리의 다른 글
4/24 Homework - 전화번호 관리/ Scanner next(),nextLine() (0) | 2024.04.24 |
---|---|
[JAVA] Map (0) | 2024.04.24 |
4/23 Homework - 야구게임, 로또생성기 (0) | 2024.04.24 |
[JAVA] Set (0) | 2024.04.23 |
[JAVA] Stack, Queue, (홈페이지 뒤로가기 구현), 정렬(Sort) (1) | 2024.04.22 |