๐ŸŒฒ equals์™€ hashCode๋ž€?

equals์™€ hashCode๋Š” ๋ชจ๋“  Java ๊ฐ์ฒด์˜ ๋ถ€๋ชจ ๊ฐ์ฒด์ธ Object ํด๋ž˜์Šค์— ์ •์˜๋˜์–ด ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ Java์˜ ๋ชจ๋“  ๊ฐ์ฒด๋Š” Object ํด๋ž˜์Šค์— ์ •์˜๋œ equals์™€ hashCode ํ•จ์ˆ˜๋ฅผ ์ƒ์†๋ฐ›๊ณ  ์žˆ๋‹ค.

 

๐ŸŒฑ equals() ๋ž€?

public boolean equals(Object obj) {
    return (this == obj);
}

 

๐Ÿซง '==' ์—ฐ์‚ฐ์ž์™€ ๋™์ผ์„ฑ(identity)

์ž๋ฐ”์—์„œ '==' ์—ฐ์‚ฐ์ž๋Š” ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๋น„๊ตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์— ํ• ๋‹น๋˜์–ด ์žˆ๋‹ค๋ฉด ๋‘ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•œ๋‹ค. ๋”ฐ๋ผ์„œ '==' ์—ฐ์‚ฐ์ž๋Š” ์ฃผ๋กœ ๊ธฐ๋ณธ ํƒ€์ž…์˜ ๊ฐ’์ด๋‚˜ ๊ฐ์ฒด์˜ ์ฐธ์กฐ ์ž์ฒด๋ฅผ ๋น„๊ตํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ๋™๋“ฑ์„ฑ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํŒ๋‹จํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด์˜ ๋‚ด์šฉ์ด๋‚˜ ์ƒํƒœ๋ฅผ ๋น„๊ตํ•˜๊ณ ์ž ํ•  ๋•Œ๋Š” '==' ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.

 

๋™์ผ์„ฑ์˜ ๋น„๊ต๋Š” ๊ฐ์ฒด์˜ ์‹ค์ œ ๋‚ด์šฉ๋ณด๋‹ค๋Š” ๊ฐ์ฒด๊ฐ€ ์œ„์น˜ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์— ์ดˆ์ ์„ ๋งž์ถ˜๋‹ค.

 

๐Ÿซง 'equals()' ๋ฉ”์„œ๋“œ์™€ ๋™๋“ฑ์„ฑ(equality)์˜ ๊ด€๊ณ„

equals() ๋ฉ”์„œ๋“œ๋Š” ๊ฐ์ฒด์˜ ๋‚ด์šฉ์ด๋‚˜ ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€์ง€๋ฅผ ํŒ๋‹จํ•œ๋‹ค.

์ž๋ฐ”์˜ 'Object' ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ ๊ธฐ๋ณธ ์ƒํƒœ์˜ 'equals()' ๋ฉ”์„œ๋“œ๋Š” '==' ์—ฐ์‚ฐ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ฅผ ๋น„๊ตํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ๊ฐ์ฒด์˜ ๋™๋“ฑ์„ฑ ๋น„๊ต๋ฅผ ์œ„ํ•ด์„œ๋Š” 'equals()' ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ๊ฐ์ฒด์˜ ์ƒํƒœ๋‚˜ ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

 

๐ŸŒฑ hashCode() ๋ž€?

hashCode ๋ฉ”์„œ๋“œ๋Š” ์‹คํ–‰ ์ค‘์—(Runtime) ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ฒˆ์ง€๋ฅผ ์ด์šฉํ•ด ์œ ์ผํ•œ integer ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด ๊ฐ’์€ ํ•ด์‹œ ๊ธฐ๋ฐ˜์˜ ์ปฌ๋ ‰์…˜์—์„œ ๊ฐ์ฒด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

 

๐Ÿซง 'hashCode()' ๋ฉ”์„œ๋“œ์™€ ๋™๋“ฑ์„ฑ(equality)

'equals()' ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•  ๋•Œ๋Š” 'hashCode()' ๋ฉ”์„œ๋“œ๋„ ํ•จ๊ป˜ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ž๋ฐ”์˜ ์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›Œํฌ(HashTable, HashSet, HashMap)์—์„œ ๊ฐ์ฒด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, 'equals()' ๋ฉ”์„œ๋“œ๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋‘ ๊ฐ์ฒด๋Š” ๊ฐ™์€ 'hashCode()' ๊ฐ’์„ ๊ฐ€์ ธ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ ๋™๋“ฑํ•œ ๊ฐ์ฒด๋Š” ๋ฐ˜๋“œ์‹œ ๊ฐ™์€ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

 

๐Ÿค” equals()์™€ hashcode() ์ค‘ ํ•˜๋‚˜๋งŒ ์žฌ์ •์˜ ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

equals()๋งŒ ์žฌ์ •์˜ํ•˜๋ฉด ๊ฐ™์€ ๊ฐ’ ๊ฐ์ฒด๋ผ๋„ hashcode๊ฐ’์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ HashTable ๊ฐ™์€ ํ•ด์‹œ๊ฐ’์„ Key ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์—์„œ ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์ €์žฅ๋œ ๋ฒ„ํ‚ท์„ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค.

๋ฐ˜๋Œ€๋กœ hashcode()๋งŒ ์žฌ์ •์˜ํ•˜๋ฉด hashcode() ๋ฉ”์„œ๋“œ๊ฐ€ ๋งŒ๋“  ํ•ด์‹œ๊ฐ’์„ ์ด์šฉํ•ด ๊ฐ์ฒด๊ฐ€ ์ €์žฅ๋œ ๋ฒ„ํ‚ท์„ ์ฐพ์„ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์ž์‹ ๊ณผ ๊ฐ™์€ ๊ฐ์ฒด์ธ์ง€ ๊ฐ’์„ ๋น„๊ตํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— null์„ ๋ฆฌํ„ดํ•˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์›ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค.


์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ๊ฐ์ฒด์˜ ์ •ํ™•ํ•œ ๋™๋“ฑ, ๋™์ผ ๋น„๊ต๋ฅผ ์œ„ํ•ด์„œ(ํŠนํžˆ Hash ๊ด€๋ จ ์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉ ์‹œ) Object์˜ equals() ๋ฉ”์„œ๋“œ, hashCode() ๋ฉ”์„œ๋“œ ๋‘˜ ๋‹ค ์žฌ์ •์˜ํ•˜์—ฌ ๋…ผ๋ฆฌ์  ๋™๋“ฑ ๊ฐ์ฒด์ผ ๊ฒฝ์šฐ ๋™์ผํ•œ ํ•ด์‹œ์ฝ”๋“œ๊ฐ€ ๋ฆฌํ„ด๋˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.


๐ŸŒฒ equals() Override์˜ ํ•„์š”์„ฑ

public class Student {
    private Long id;
    private String name;
    private int age;

    public Student(Long id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

์œ„์™€ ๊ฐ™์ด Student ํด๋ž˜์Šค๊ฐ€ ์žˆ์„ ๋•Œ name๊ณผ age ํ•„๋“œ๊ฐ’์ด ๋˜‘๊ฐ™์€ ๋‘ Student ๊ฐ์ฒด๋ฅผ Object์˜ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์€ equals()๋กœ ๋น„๊ตํ•  ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

 

@Test
public void equalsTest() {

    Student s1 = new Student(1L, "๊น€๊ฐ€๋‚˜", 20);
    Student s2 = new Student(1L, "๊น€๊ฐ€๋‚˜", 20);

    System.out.println("s1.equals(s2) = " + s1.equals(s2));
}
s1.equals(s2) = false

๊ฒฐ๊ณผ๋Š” false๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

ํ•ด๋‹น ๊ฐ์ฒด๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ์— ์œ„์น˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ(Identity) ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ƒ์œผ๋กœ๋Š” ๊ฐ™์€ ๊ฐ’์„ ์ง€๋‹ˆ๋ฏ€๋กœ ๊ฐ™์€ ๊ฐ์ฒด๋กœ ์ธ์‹๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ๋™๋“ฑ์„ฑ(Equality)์„ ์œ„ํ•ด ๊ฐ’์œผ๋กœ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋„๋ก equals ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

@Override
public boolean equals(Object obj) {
    if (this == obj) return true; // ์ฐธ์กฐ๊ฐ’์ด ๊ฐ™์€ ๊ฒฝ์šฐ true ๋ฆฌํ„ด
    if (obj == null || getClass() != obj.getClass()) return false; // ๋น„๊ตํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ null์ด๊ฑฐ๋‚˜ ํด๋ž˜์Šค ๋ถˆ์ผ์น˜ ์‹œ false ๋ฆฌํ„ด

    Student student = (Student) obj;
    return (this.getId() == student.getId()); // ๊ฐ์ฒด ๊ณ ์œ  id ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ๋ฆฌํ„ด
}

์ด์ œ equals์— ์˜ํ•œ ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐ๋๋‹ค.

ํ•˜์ง€๋งŒ Student๋ฅผ HashSet๊ณผ ๊ฐ™์€ ์ž๋ฃŒ๊ตฌ์กฐ์— ์ €์žฅํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋œ๋‹ค.

 

๐ŸŒฒ hashCode() Override์˜ ํ•„์š”์„ฑ

์•ž์„œ ์„ค๋ช…ํ•œ ๋Œ€๋กœ HashTable์ด๋‚˜ HashSet, HashMap๊ณผ ๊ฐ™์€ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์ž๋ฃŒ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์œ„์น˜๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด hashCode๋ฅผ ์ด์šฉํ•œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด Student์˜ HashCode๋ฅผ ์กฐํšŒํ•ด ๋ณด๋ฉด ์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ๊นŒ?

s1.equals(s2) = true
s1.hashCode() = 3093793
s2.hashCode() = 4023425

Object ํด๋ž˜์Šค์˜ hashCode() ๋ฉ”์„œ๋“œ๋Š” ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— s1๊ณผ s2๋Š” ๋‹ค๋ฅธ ํ•ด์‹œ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด hashCode ๋ฉ”์„œ๋“œ๋„ Student ํด๋ž˜์Šค์— ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์—ฌ ์ˆ˜์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

@Override
public int hashCode() {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
}

์ด์ฒ˜๋Ÿผ Student ํด๋ž˜์Šค์— hashCode๋ฅผ ์œ„์™€ ๊ฐ™์ด ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•  ๊ฒฝ์šฐ, ๊ฐ์ฒด ๊ณ ์œ  id๊ฐ’์ด ๊ฐ™์œผ๋ฉด hashCode ๊ฐ’๋„ ๊ฐ™์•„์ง€๊ฒŒ ๋œ๋‹ค.

 

 

[Java] equals์™€ hashCode ํ•จ์ˆ˜

์ž๋ฐ”์˜ ๋™๋“ฑ์„ฑ๊ณผ ๋™์ผ์„ฑ ์ดํ•ดํ•˜๊ธฐ

[java] hashcode()์™€ equals() ๋ฉ”์„œ๋“œ๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•˜๊ณ  ์™œ ์‚ฌ์šฉํ• ๊นŒ?