ejyoo's 개발 노트

Hash - equals()와 hash() 메서드 구현 본문

BackEnd/Java

Hash - equals()와 hash() 메서드 구현

ejyoovV 2021. 3. 8. 19:13

ejyoo.tistory.com/72?category=930353

 

해시(Hash) 알고리즘

📝오늘 수업 도중 해시 알고리즘에 대해 들었는데. 정보를 조금 더 찾아보기로 했다. 본 글은 타 블로그에서 발췌한 내용으로 구성되었으며, 작성자가 수업을 들은 내용도 조금 추가가 되어있

ejyoo.tistory.com

지난 포스팅에서 Hash에 대한 포스팅을 올린 이력이 있다.

본 포스트는 테스트 코드만 작성한다.

 

💡 객체 클래스화 후 객체 값 비교

public class Main {
	public static void main(String[] args) {
		Person p1 = new Person(1, "홍길동");
		Person p2 = new Person(1, "홍길동");
		
		System.out.println("p1.equals(p2) : " + p1.equals(p2));
	}
}

class Person{
	private int id;
	private String name;
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

Person p1 과 Person p2 는 우리가 보기엔 같은 값이 들어있다. 

하지만 그 결과값은 true 가 아닌 false 가 나온다.

이 이유는 equals와 hashCode를 오버라이드 하지 않고 

Object 의 equals를 사용하여 멤버를 비교하였기 때문에 false가 나온것이다.

Object에 정의된 equals를 사용하는 경우, 생성한 객체에 대해 값이 같은지 비교할 수 없다.

 

이에 대한 해결방법은

Object에 구현된 메서드를 오버라이드 하여 Object에 구현된 equals, hashCode 메서드를 사용하지 않고 새로운 형태를 사용한다.

equals와 hashCode 메서드를 오버라이드 해보자.

 

💡 오버라이드 구현(equals, hashCode)

이클립스 자동완성 기능을 활용하여 만든다.

public class Main {
	public static void main(String[] args) {
		Person p1 = new Person(1, "홍길동");
		Person p2 = new Person(1, "홍길동");
		
		System.out.println("p1.equals(p2) : " + p1.equals(p2));
	}
}

class Person{
	private int id;
	private String name;
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;//소수 : 1과 자기자신으로만 나눌 수 있는 것.
		int result = 1;
		result = prime * result + id;//객체의 id 값
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)//this : p1 = p1넣은 경우 (this.p1.equals(object))
			return true;
		if (obj == null)//p1.equals(null)
			return false;
//		getClass() : Object가 속한 클래스정보를 가져옴
//		Object를 만들라면 Class가 존재해야된다. 클래스 없이 Object를 만들 수 없다.
		if (getClass() != obj.getClass())//getClass() : Person , obj.getClass() : Person
			return false;
		Person other = (Person) obj;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

위의 코드를 살펴본다.

 

오버라이드 된 hashCode에서

final int prime = 31;

이부분은, 해시코드는 기본적으로 임의의 소수로 설정한다.

오버라이드 시 소수 31을 사용하여 구현한다.

 

나머지는 코드 그대로 해석하면 된다.

이상태에서 다시 실행을 해본다.

결과값이 True가 됨을 확인할 수 있다.

p1과 p2를 equals가 아닌 비교연산자 '=='를 사용한 경우 아래와 같이 표시된다.

public class Main {
	public static void main(String[] args) {
		Person p1 = new Person(1, "홍길동");
		Person p2 = new Person(1, "홍길동");
		
		System.out.println("p1.equals(p2) : " + p1.equals(p2));
		
		System.out.println("p1 == p1 : " + (p1==p1));
		System.out.println("p1 == p2 : " + (p1==p2));
	}
}

class Person{
	private int id;
	private String name;
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

💡 Set에 객체 저장해보기

중복 저장이 되지 않는 Set을 사용하여 생성한 Person 객체를 넣어본다.

equals와 hashCode를 오버라이드하여 구현했기 때문에 

구현한 객체에 대한 비교를 할 수 있는 상태이므로

위의 코드에서 같다고 나온 p1, p2 객체가 Set에 들어갔을 때, 

최초 삽입됐던 p1 객체만 들어가게 되고 p2 객체는 중복으로 인하여 삽입이 취소된다.

아래의 코드를 확인해본다.

package baekjoonProject;

import java.util.HashSet;
import java.util.Set;

public class Main {
	public static void main(String[] args) {
		Person p1 = new Person(1, "홍길동");
		Person p2 = new Person(1, "홍길동");
		
		System.out.println("p1.equals(p2) : " + p1.equals(p2));
		
		System.out.println("p1 == p1 : " + (p1==p1));
		System.out.println("p1 == p2 : " + (p1==p2));
		System.out.println("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■");
		Set<Person> set = new HashSet<Person>();
		System.out.println("set.add(p1) 성공 여부 : " + set.add(p1));
		System.out.println("set.add(p2) 성공 여부 : " + set.add(p2));
		
	}
}

class Person{
	private int id;
	private String name;
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

Set에 p2는 add() 실패한 것을 확인할 수 있다. set 변수의 사이즈와 데이터를 찍어본다.

아래 코드를 추가한다.

System.out.println("set의 size() : " + set.size());
System.out.println("set의 내용");
for(Person p : set) {
	System.out.println(p.getId() + " : " + p.getName());
}

 

'BackEnd > Java' 카테고리의 다른 글

Properties  (0) 2021.03.08
Map  (0) 2021.03.08
TreeSet  (0) 2021.03.07
Set  (0) 2021.03.07
List의 정렬(Sort) - interface : Comparable, Comparator (3)  (0) 2021.03.06