๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’กCS/Java

[Java] equals()์™€ hashCode()(+ ๋™์ผ์„ฑ, ๋™๋“ฑ์„ฑ)

by hyeon-z 2023. 6. 9.

 

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

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

 

๋™์ผ์„ฑ(Identity), ๋™๋“ฑ์„ฑ(Equality)

 

ํ•จ์ˆ˜๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์ „ ์•Œ์•„๋‘๋ฉด ์ข‹์„ ๊ฐœ๋…์ธ ๊ฒƒ ๊ฐ™์•„์„œ ๋จผ์ € ์ •๋ฆฌํ•˜์˜€๋‹ค.

 

๋™์ผ์„ฑ(Identity)

 

๋™์ผ์„ฑ์€ ๋น„๊ต ๋Œ€์ƒ์˜ ๋‘ ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๊ฐ€ ๊ฐ™์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

์ž๋ฐ”์—์„œ ๋น„๊ต์—ฐ์‚ฐ์ž(==)๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

public class Main {
    static class Person{
        int age;

        public Person(int age) {
            this.age = age;
        }
    }

    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = p1;

        System.out.println(p1 == p2);
    }
}

p2๋Š” ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , p1์„ ๋Œ€์ž…๋ฐ›๋Š”๋‹ค.

์ฆ‰, p1๊ณผ p2๋Š” ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์— ์œ„์น˜ํ•œ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋‹ค.

๊ฐ์ฒด๋Š” ๊ฐ์ž์˜ ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด ์‹๋ณ„์ž๊ฐ€ ๊ฐ™๋‹ค๋ฉด ๋™์ผํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•œ๋‹ค. 

 

๋™๋“ฑ์„ฑ(Equality)

 

๋น„๊ต ๋Œ€์ƒ์˜ ๋‘ ๊ฐ์ฒด๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋™์ผํ•œ ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๊ณ  ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค. 

์ž๋ฐ”์˜ ๋™๋“ฑ์„ฑ์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” equals์™€ hashcode๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์•ผ ํ•œ๋‹ค. (ํ•จ์ˆ˜์˜ ๋‚ด์šฉ์€ ์•„๋ž˜์„œ ์ž์„ธํžˆ ๋‹ค๋ฃฐ ์˜ˆ์ •) 

 

public class Main {
    static class Person{
        int age;

        public Person(int age) {
            this.age = age;
        }
    }

    @Override
    public int hashCode() {
        ...
    }

    @Override
    public boolean equals(Object obj) {
        ...
    }

    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);

        System.out.println(p1 == p2);  // false
        System.out.println(p1.equals(p2));  // true
    }
}

p1๊ณผ p2๋Š” ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง€์ง€๋งŒ 20์ด๋ผ๋Š” ๊ฐ™์€  ๊ฐ’์„ ๊ฐ€์ง„๋‹ค.

๋”ฐ๋ผ์„œ p1๊ณผ p2๋Š” ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๋ฏ€๋กœ ๋™๋“ฑํ•˜๋‹ค.

 

p1๊ณผ p2๋ฅผ ์•ž์„œ ๋™์ผ์„ฑ์„ ๋น„๊ตํ–ˆ๋˜ ๋น„๊ต์—ฐ์‚ฐ์ž(==)๋กœ ๋น„๊ตํ•˜๋ฉด ๋‹ค๋ฅธ ์ฃผ์†Œ๊ฐ’์„ ๊ฐ€์ง€๋ฏ€๋กœ false๊ฐ’์ด ์ถœ๋ ฅ๋œ๋‹ค.


equals()

Objectํด๋ž˜์Šค์˜ equals๋ฉ”์„œ๋“œ 

 

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

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋น„๊ต ์—ฐ์‚ฐ์ž๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๊ณ  ์žˆ๋‹ค.

์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋˜ ๊ฒƒ์„ ๋ณด๋ฉด ๋น„๊ต ์—ฐ์‚ฐ์ž๋Š” ๊ฐ์ฒด์˜ ๋™์ผ์„ฑ(Identity)์„ ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

 

equals()์˜ override ํ•„์š”์„ฑ

 

๊ธฐ์กด์˜ equals ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ ๊ฐ’์ด ๊ฐ™์•„๋„ ๊ฐ์ฒด์˜ ์ฃผ์†Œ๊ฐ’์ด ๋‹ค๋ฅด๋ฉด false๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค

 

ํ•˜์ง€๋งŒ ์ด๋Š” ์ปดํ“จํ„ฐ์ ์ธ ๊ด€์ ์—์„œ ๋ฐ”๋ผ๋ณธ ๊ฒƒ์ด๋‹ค.

 

์™ธ๋ถ€์ ์ธ ๊ด€์ ์—์„œ๋Š” ๋‘ ๊ฐ์ฒด๋Š” ๋˜‘๊ฐ™์€ Person ํด๋ž˜์Šค ํƒ€์ž…์ด๊ณ  ๋˜‘๊ฐ™์€ ๋‚˜์ด ๊ฐ’ 20์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์ฆ‰, ์‚ฌ์šฉ ์ž…์žฅ์—์„œ๋Š” ๋‘ ๊ฐ์ฒด๋Š” ๊ฐ™์€ ๊ฐ์ฒด์ด๋‹ค..

 

๋”ฐ๋ผ์„œ ๋™๋“ฑ์„ฑ์„ ์œ„ํ•ด ๊ฐ’์œผ๋กœ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋„๋ก equals๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ์žฌ์ •์˜ํ•œ๋‹ค.

 

equals() override

 

public class Main {
    static class Person {
        int age;

        public Person(int age) {
            this.age = age;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Person person = (Person) o;
            return Objects.equals(this.age, person.age);
        }
    }


    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);

        System.out.println(p1.equals(p2));
    }
}

 

์žฌ์ •์˜ํ•œ ์ฝ”๋“œ๋ฅผ ํ•œ ์ค„์”ฉ ์‚ดํŽด๋ณด์ž.

if (this == o) return true;

ํ˜„์žฌ ๊ฐ์ฒด์™€ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์œผ๋ฉด(๋™์ผํ•˜๋ฉด) true๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

๋‘ ๊ฐ์ฒด๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฏ€๋กœ ๋™๋“ฑํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

if (o == null || getClass() != o.getClass()) return false;

๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ์ฒด๊ฐ€ null์ด๊ฑฐ๋‚˜ Personํƒ€์ž…์ด ์•„๋‹ˆ๋ผ๋ฉด false๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

๋‘ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค์ผ ๊ฒฝ์šฐ ๋™๋“ฑ์„ฑ์„ ๋น„๊ตํ•  ํ•„์š” ์—†์ด ๋‹ค๋ฅธ ๊ฐ’์ด๋‹ค.

 

Person person = (Person) o;
return Objects.equals(this.age, person.age);

์œ„์˜ ๊ฒฝ์šฐ๋ฅผ ๋ชจ๋‘ ํ†ต๊ณผํ–ˆ๋‹ค๋ฉด ์บ์ŠคํŒ…์„ ํ†ตํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐ์ฒด๋ฅผ Personํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

๊ทธ ํ›„ ๋‘ ๊ฐ์ฒด์˜ age ์ฆ‰, ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ๊ฐ™์€์ง€ ํŒ๋ณ„ํ•œ๋‹ค.

 

์ด๋•Œ Objectsํด๋ž˜์Šค์˜ equals๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

 

๐Ÿค” Objectsํด๋ž˜์Šค์˜ equals๋ฉ”์„œ๋“œ๋ž‘ override ํ•œ equalsํ•จ์ˆ˜๋ž‘ ๋‚ด์šฉ์ด ๋˜‘๊ฐ™์€ ๊ฒƒ ๊ฐ™์€๋ฐ ๊ตณ์ด ์™œ ์žฌ์ •์˜๋ฅผ ํ• ๊นŒ? 

 

์žฌ์ •์˜ํ•œ ํ•จ์ˆ˜์—์„œ Objects.equals๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ์„ ๋ณด๊ณ  "๊ทธ๋Ÿผ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€?"๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋Š”๋ฐ ์ฐฉ๊ฐ์ด์—ˆ๋‹ค.

 

๊ฐ์ฒด ์ž์ฒด๋ฅผ equalsํ•จ์ˆ˜์— ๋„ฃ๊ฒŒ ๋˜๋ฉด ๊ฒฐ๊ตญ return (a == b) || (a!= null && a == b)๊ฐ€ ๋˜๋ฏ€๋กœ ๋™๋“ฑ์„ฑ์„ ํŒ๋‹จํ•  ์ˆ˜ ์—†๋‹ค.

๋”ฐ๋ผ์„œ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋น„๊ตํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ ๋„ฃ์–ด์„œ ์žฌ์ •์˜ํ•œ ๊ฒƒ์ด๋‹ค.  

 

๐Ÿ’ก Objectํด๋ž˜์Šค์™€ Objectsํด๋ž˜์Šค ์ฐจ์ด 

Object class

- java.langํŒจํ‚ค์ง€์— ํฌํ•จ
- ๋ชจ๋“  ์ž๋ฐ” ํด๋ž˜์Šค์˜ ์ตœ๊ณ  ์กฐ์ƒ ํด๋ž˜์Šค
-  ์ž๋ฐ”์˜ ๋ชจ๋“  ํด๋ž˜์Šค๋Š” Object ํด๋ž˜์Šค์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Objects class
- java.util ํŒจํ‚ค์ง€์— ํฌํ•จ
- ๊ฐ์ฒด ๋น„๊ต, ํ•ด์‹œ์ฝ”๋“œ ์ƒ์„ฑ, null ์—ฌ๋ถ€, ๊ฐ์ฒด ๋ฌธ์ž์—ด ๋ฆฌํ„ด ๋“ฑ์˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ •์  ๋ฉ”์„œ๋“œ๋“ค๋กœ ๊ตฌ์„ฑ๋œ Object์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค

 

+) ์ฐธ๊ณ 

Stringํด๋ž˜์Šค์—๋Š” ์ด๋ฏธ ๋™๋“ฑ์„ฑ์„ ํŒ๋ณ„ํ•˜๋Š” equals๋ฉ”์„œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๋‹ค.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String aString = (String)anObject;
        if (coder() == aString.coder()) {
            return isLatin1() ? StringLatin1.equals(value, aString.value)
                              : StringUTF16.equals(value, aString.value);
        }
    }
    return false;
}

hashCode()

 

๊ฐ์ฒด์˜ ์ฃผ์†Œ ๊ฐ’์„ ์ด์šฉํ•ด์„œ ํ•ด์‹ฑ(hashing) ๊ธฐ๋ฒ•์„ ํ†ตํ•ด ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“  ํ›„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ฐ์ฒด๋Š” ๊ฐ™์€ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค.

 

์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด ํ•ด์‹œ ์ฝ”๋“œ๋Š” ์ฃผ์†Œ๊ฐ’์€ ์•„๋‹ˆ๊ณ , ์ฃผ์†Œ๊ฐ’์œผ๋กœ ๋งŒ๋“  ๊ณ ์œ ํ•œ ์ˆซ์ž๊ฐ’์ด๋‹ค.

 

public class Main {
    static class Person {
        int age;

        public Person(int age) {
            this.age = age;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Person person = (Person) o;
            return Objects.equals(this.age, person.age);
        }
    }


    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);
        Person p3 = p1;

        System.out.println(p1.hashCode());  // 1521118594
        System.out.println(p2.hashCode());  // 1940030785
        System.out.println(p3.hashCode());  // 1521118594
    }
}

 

Objectํด๋ž˜์Šค์˜ hashcode๋ฉ”์„œ๋“œ

 

public native int hashCode();

 native ํ‚ค์›Œ๋“œ๊ฐ€ ๋“ค์–ด๊ฐ„ ๋ฉ”์„œ๋“œ๋Š” OS๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋œปํ•œ๋‹ค.

 

๐Ÿ’กJNI(Java Native Interface)

์ž๋ฐ” ๊ฐ€์ƒ๋จธ์‹ (JVM) ์œ„์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ์ž๋ฐ”์ฝ”๋“œ๊ฐ€ ๋„ค์ดํ‹ฐ๋ธŒ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ(ํ•˜๋“œ์›จ์–ด์™€ ์šด์˜ ์ฒด์ œ ํ”Œ๋žซํผ์— ์ข…์†๋œ ํ”„๋กœ๊ทธ๋žจ๋“ค) ๊ทธ๋ฆฌ๊ณ  C, C++ ๊ทธ๋ฆฌ๊ณ  ์–ด์…ˆ๋ธ”๋ฆฌ ๊ฐ™์€ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๋กœ ์ž‘์„ฑ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ ๋ฐ˜๋Œ€๋กœ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ”„๋ ˆ์ž„์›Œํฌ

์œ„์—์„œ ์„ค๋ช…ํ•œ native ์ฝ”๋“œ ์ค‘ ํ•˜๋‚˜๊ฐ€ hashCode() ๋ฉ”์„œ๋“œ์ด๋‹ค.

์ด ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์„œ๋“œ๋Š” OS์— C์–ธ์–ด๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ์–ด ๊ทธ ์•ˆ์˜ ๋‚ด์šฉ์€ ๋ณผ ์ˆ˜ ์—†๊ณ , ์˜ค๋กœ์ง€ ์‚ฌ์šฉ๋งŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋งˆ์น˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ์ •์˜๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

 

hashcode()์˜ override ํ•„์š”์„ฑ

 

๐Ÿค” ์™œ hashcode()๋Š” equals()์™€ ํ•จ๊ป˜ override ๋˜์–ด์•ผ ํ• ๊นŒ? 

 

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด ๋‘ ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์„ ์‹œ,  Collection Framework(HashSet, HashMap, HashTable)์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ฒœ์ฒœํžˆ ์‚ดํŽด๋ณด์ž.

 

equals๋งŒ ์žฌ์ •์˜ํ•  ๊ฒฝ์šฐ

 

๐Ÿ‘† List๋ฅผ ํ†ตํ•œ ์ถœ๋ ฅ

public class Main {
    static class Person {
        int age;

        public Person(int age) {
            this.age = age;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Person)) return false;
            Person person = (Person) o;
            return age == person.age;
        }
    }

    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);


        System.out.println(p1.hashCode());  // 1521118594
        System.out.println(p2.hashCode());  // 1940030785

        List<Person> people = new ArrayList<>();
        people.add(p1);
        people.add(p2);

        System.out.println(people.size());  // 2
    }
}

p1๊ณผ p2๊ฐ์ฒด๋Š” ํ•ด์‹œ์ฝ”๋“œ, ์ฆ‰ ์ฃผ์†Œ ๊ฐ’์ด ๋‹ค๋ฆ„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ๋œ๋‹ค.

๋งˆ์ง€๋ง‰์— Person ๊ฐ์ฒด 2๊ฐœ๋ฅผ ArrayList์ž๋ฃŒํ˜•์— ๋„ฃ์€ ํ›„ ๋ฆฌ์ŠคํŠธ์˜ ํฌ๊ธฐ(๊ธธ์ด)๋Š” 2๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

 

๐Ÿ‘† Set์„ ํ†ตํ•œ ์ถœ๋ ฅ

 

๐Ÿšจ์š”๊ตฌ์‚ฌํ•ญ ์ถ”๊ฐ€๐Ÿšจ

Collection์— ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” Person ๊ฐ์ฒด๋งŒ ๋„ฃ์–ด๋ผ.

public class Main {
	... 
    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);

        Set<Person> people = new HashSet<>();
        people.add(p1);
        people.add(p2);

        System.out.println(people.size());  // 2
    }
}

 

List์ž๋ฃŒํ˜• ๋Œ€์‹  ์ค‘๋ณต๋œ ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” Set ์ž๋ฃŒํ˜•์„ ์ด์šฉํ•ด ๋ณด์ž.

ArrayList์—์„œ HashSet์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋Š” 2๊ฐ€ ๋‚˜์™”๋‹ค. (โ“โ“โ“)

 

Person๊ฐ์ฒด์˜ age๊ฐ’์ด ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ๊ฐ์ฒด๋กœ ํŒ๋ณ„ํ•˜๋„๋ก equals๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•˜์˜€์œผ๋ฏ€๋กœ ๊ฒฐ๊ณผ ๊ฐ’์€ 1์ด ๋‚˜์™”์–ด์•ผ ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ์˜ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋‹ค.

 

p1๊ณผ p2๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™๋‹ค๊ณ  ์ •์˜ํ•˜์˜€์ง€๋งŒ ํ•ด์‹œ์ฝ”๋“œ๊ฐ€ ๋‹ค๋ฅด๋ฏ€๋กœ ์ค‘๋ณต๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋œ ๊ฒƒ์ด๋‹ค.  

 

hashCode์™€ equals ๋™์ž‘ ์ˆœ์„œ

 

์œ„์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š” ์ด์œ ๋Š” hash ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” Collection(HashMap, HashSet, HashTable)์€ ๊ฐ์ฒด๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€์ง€ ๋น„๊ตํ•  ๋•Œ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์€ ๊ณผ์ •์„ ๊ฑฐ์น˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

1. ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๊ทธ ๋ฐ์ดํ„ฐ์˜ hashCode()์˜ ๋ฆฌํ„ด ๊ฐ’์„ ๋น„๊ตํ•˜๊ณ  ๊ฐ™์œผ๋ฉด equals() ์‹คํ–‰, ๋‹ค๋ฅด๋ฉด false๋ฅผ return ํ•œ๋‹ค.

2. equals()์˜ ๋ฆฌํ„ด ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ๊ฐ™์œผ๋ฉด true๋ฅผ retun ํ•˜๊ณ  ๋‹ค๋ฅด๋ฉด false๋ฅผ return ํ•œ๋‹ค.

 

๋”ฐ๋ผ์„œ Personํด๋ž˜์Šค์—์„œ equals()๋ฅผ override ํ•  ๋•Œ hashCode๋ฅผ override ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฐ”๋กœ false๋ฅผ ๋ฆฌํ„ดํ•ด ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ํŒ๋ณ„ํ•˜๊ฒŒ ๋œ๋‹ค.   

 

=> ๋”ฐ๋ผ์„œ equals๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ ํ•  ๋•Œ๋Š” ๊ผญ hashCode๋ฉ”์„œ๋“œ๋„ ์žฌ์ •์˜ ํ•ด์•ผ ํ•œ๋‹ค.

 

hashCode() override

 

public class Main {
    static class Person {
		...

        @Override
        public boolean equals(Object o) {
            ...
        }

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


    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);

        Set<Person> people = new HashSet<>();
        people.add(p1);
        people.add(p2);

        System.out.println(people.size());  // 1
    }
}

๋ฐ˜ํ™˜๋˜๋Š” ํ•ด์‹œ์ฝ”๋“œ ๊ฐ’์„ ๊ฐ์ฒด์˜ ์ฃผ์†Œ๊ฐ’์ด ์•„๋‹Œ Person๊ฐ์ฒด์˜ age ๊ฐ’์„ ์ด์šฉํ•ด ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•œ๋‹ค.

 

๐Ÿ’ก Objects.hash()

public static int hash(Object... values) {
    return Arrays.hashCode(values);
}

 

๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ฃผ์–ด์ง„ ๊ฐ’๋“ค์„ ์ด์šฉํ•ด์„œ ๊ณ ์œ ํ•œ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
์ฆ‰, ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ๊ฐ์ฒด๋“ค์˜ ํ•„๋“œ๋กœ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด, ๋™์ผํ•œ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด, ์ด ํ•ด์‹œ์ฝ”๋“œ ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์žฌ์ •์˜ํ•œ equals()๊ฐ€ ๋™๋“ฑ ๋น„๊ต์— ์ด์šฉํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.
 
Objects.hash()๋Š” hashCode ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ„ํŽธํžˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ์ด์ง€๋งŒ ์†๋„๊ฐ€ ๋А๋ฆฌ๋‹ค. ์ธ์ž๋ฅผ ๋‹ด๊ธฐ ์œ„ํ•œ ๋ฐฐ์—ด์ด ๋งŒ๋“ค์–ด์ง€๊ณ  ์ธ์ž ์ค‘ ๊ธฐ๋ณธ ํƒ€์ž…์ด ์žˆ๋‹ค๋ฉด ๋ฐ•์‹ฑ๊ณผ ์–ธ๋ฐ•์‹ฑ๋„ ๊ฑฐ์ณ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๐Ÿค” ๊ฐ์ œ์ž์ฒด์˜ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ์–ป๊ณ  ์‹ถ์œผ๋ฉด ์–ด๋–กํ•˜์ง€? ์ด๋ฏธ hashCode๋Š” ์žฌ์ •์˜ํ•ด์„œ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ..   

 

hashCode()์˜ ์›๋ž˜ ๋ชฉ์ ์€ ๊ฐ์ฒด์˜ ์ฃผ์†Œ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด์‹ฑ์—์„œ ๊ณ ์œ ํ•œ ์ˆซ์ž๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์˜ ๋™์ผ์„ฑ(identity)์„ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์ด๋‹ค

 

์›๋ž˜์˜ hashCode๋ฅผ ๊ตฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ  identityHashCode()๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์ฆ‰, hashCode()๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์„œ ์“ฐ๋Š”๋ฐ, ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜๊ธฐ ์ „์˜ ์›์กฐ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

System.identityHashCode()๋Š” ๋”ฐ๋กœ ๋…๋ฆฝ๋œ ์‹œ์Šคํ…œ ๋ฉ”์„œ๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์†Œ ๊ฐ’์ด ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋Œ€ํ•ด ํ•ญ์ƒ ๋‹ค๋ฅธ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค. 

 

์˜ˆ์‹œ

public class Main {
    static class Person {
        ...

        @Override
        public boolean equals(Object o) {
            ...
        }

        @Override
        public int hashCode() {
            ...
        }
    }


    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(20);

        System.out.println(p1.hashCode()); // 51
        System.out.println(p2.hashCode());  // 51
        
        System.out.println(System.identityHashCode(p1));  // 1521118594
        System.out.println(System.identityHashCode(p2));  // 1940030785
    }
}

 

hashCode ์ฃผ์˜์‚ฌํ•ญ

 

hashCode๊ฐ€ ๊ณ ์œ ํ•œ ๊ฐ’์€ ์•„๋‹ˆ๋‹ค!

 

๋ณดํ†ต ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ƒ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ์ฃผ์†Œ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋Š” ๊ฒฐ์ฝ” ๊ฐ™์€ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค. ํ•˜์ง€๋งŒ ์˜ˆ์™ธ๊ฐ€ ์žˆ๋Š”๋ฐ, ๋ฐ”๋กœ hashCode() ๋ฉ”์„œ๋“œ๊ฐ€ intํ˜• ์ •์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

 

64๋น„ํŠธ ์ปดํ“จํ„ฐ์—์„œ ๋Œ์•„๊ฐ€๋Š” JVM(๊ฐ€์ƒ๋จธ์‹ )์€ ๊ธฐ๋ณธ์ ์œผ๋กœ 8๋ฐ”์ดํŠธ(64bit) ์ฃผ์†Œ์ฒด๊ณ„๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ํ•˜๋Š”๋ฐ, ๋งŒ์ผ 8๋ฐ”์ดํŠธ์˜ ์ฃผ์†Œ๊ฐ’์„ hashCode๋ฅผ ์ด์šฉํ•ด ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋ฉ”์„œ๋“œ์˜ ํƒ€์ž…์— ๋”ฐ๋ผ 4๋ฐ”์ดํŠธ(32bit)๋กœ ๊ฐ•์ œ ์บ์ŠคํŒ…(long → int)์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด ๊ฒน์น  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ์ผ€์ด์Šค๊ฐ€ ์กด์žฌํ•˜๊ฒŒ ๋œ๋‹ค. (Hash Collisions)

 

ํ•˜์ง€๋งŒ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•  ๋•Œ ์ด๊ฒƒ์€ ํฐ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

hashCode์™€ equals ๋™์ž‘ ์ˆœ์„œ์˜ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ๋‘ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ณผ์ •์—์„œ ๋งŒ์ผ ๋‘ ๊ฐ์ฒด์˜ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๊ฐ™์œผ๋ฉด equals() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋‘ ๊ฐ์ฒด์˜ ์ง„์งœ ์ฃผ์†Œ๋ฅผ ์ง์ ‘์ ์œผ๋กœ ๋น„๊ตํ•˜๋„๋ก ๊ตฌ์„ฑ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. (๋™์ผ์„ฑ ๋น„๊ต)

 

โœ… ์ •๋ฆฌ

ํ•ด์‹œ์ฝ”๋“œ ๊ฐ’์œผ๋กœ๋งŒ ๋‘ ๊ฐ์ฒด์˜ ๋™๋“ฑ์„ ํŒ๋ณ„ํ•˜๋ ค ํ•  ๋•Œ ์ด๋Ÿฌํ•œ ์˜ˆ์™ธ์ ์ธ ์ผ€์ด์Šค๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ธ์ง€ํ•˜๊ณ  ์žˆ์ž. 


๐Ÿ’œ ๊ฟ€ํŒ!

Intellij์—์„œ alt + insert๋ฅผ ๋ˆ„๋ฅธ ํ›„ equals ๋ฐ hashCode()๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ž๋™์œผ๋กœ ์˜ค๋ฒ„๋ผ์ด๋”ฉ๋œ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.  

 

Reference

๋™์ผ์„ฑ(Identity)๊ณผ ๋™๋“ฑ์„ฑ(Equality) - hudi.blog

์ž๋ฐ” equals / hashCode ์˜ค๋ฒ„๋ผ์ด๋”ฉ - ์™„๋ฒฝ ์ดํ•ดํ•˜๊ธฐ - Inpa Dev

equals์™€ hashCode๋Š” ์™œ ๊ฐ™์ด ์žฌ์ •์˜ํ•ด์•ผ ํ• ๊นŒ? - Tecoble

Guide to hashCode() in Java - Baeldung(ํ–ฅ์ƒ๋œ  hashCode() ๋งŒ๋“ค ๋•Œ ์ฐธ๊ณ )

์ž๋ฐ” ๊ฐ์ฒด์˜ hashCode๋Š” ๊ณ ์œ ํ•˜์ง€ ์•Š๋‹ค - Inpa Dev

๋Œ“๊ธ€