Study/Effective Java

[Effective Java 3/E] 3์žฅ ๋ชจ๋“  ๊ฐ์ฒด์˜ ๊ณตํ†ต ๋ฉ”์„œ๋“œ

youn12 2023. 5. 7. 20:14
๐Ÿ“‹ ๋ชฉ์ฐจ.

1. ์ฑ•ํ„ฐ
    .
์•„์ดํ…œ 10 - equals๋Š” ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ์ง€์ผœ ์žฌ์ •์˜ ํ•˜๋ผ
    .
์•„์ดํ…œ 11 - equals๋ฅผ ์žฌ์ •์˜ํ•˜๋ ค๊ฑฐ๋“  hashCode๋„ ์žฌ์ •์˜ํ•˜๋ผ
    .
์•„์ดํ…œ 12 - toString์„ ํ•ญ์ƒ ์žฌ์ •์˜ํ•˜๋ผ
    .
์•„์ดํ…œ 13 - clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ
    .
์•„์ดํ…œ 14 - Comparable์„ ๊ตฌํ˜„ํ• ์ง€ ๊ณ ๋ คํ•˜๋ผ.

โœ”๏ธ ๋‚ด์šฉ.

 

3. ๋ชจ๋“  ๊ฐ์ฒด์˜ ๊ณตํ†ต ๋ฉ”์„œ๋“œ

 

 Object๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ตฌ์ฒด ํด๋ž˜์Šค์ด์ง€๋งŒ. ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์ƒ์†ํ•ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค.
Object์—์„œfinal์ด ์•„๋‹Œ ๋ฉ”์„œ๋“œ(equals, hashCode, toString, clone, finalize)๋Š” ๋ชจ๋‘ ์žฌ์ •์˜๋ฅผ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋œ ๊ฒƒ์ด๋ผ ์žฌ์ •์˜ ์‹œ ์ง€์ผœ์•ผ ํ•˜๋Š” ์ผ๋ฐ˜ ๊ทœ์•ฝ์ด ๋ช…ํ™•ํžˆ ์ •์˜๋˜์–ด ์žˆ๋‹ค.

 ์ด๋ฒˆ ์žฅ์—์„œ๋Š” final์ด ์•„๋‹Œ Object ๋ฉ”์„œ๋“œ๋“ค์„ ์–ธ์ œ ์–ด๋–ป๊ฒŒ ์žฌ์ •์˜ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๋‹ค๋ฃฌ๋‹ค.
 
 - final ์€ 2์žฅ Item 8์—์„œ ๋‹ค๋ค˜์œผ๋ฏ€๋กœ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.
 - Comparable.compareTo์˜ ๊ฒฝ์šฐ Object์˜ ๋ฉ”์„œ๋“œ๋Š” ์•„๋‹ˆ์ง€๋งŒ ์ด ๋น„์Šทํ•˜์—ฌ ์ด๋ฒˆ ์žฅ์—์„œ ๊ฐ™์ด ๋‹ค๋ฃฌ๋‹ค.

.์•„์ดํ…œ 10 - equals๋Š” ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ์ง€์ผœ ์žฌ์ •์˜ ํ•˜๋ผ

 

 equals ๋ฉ”์„œ๋“œ๋Š” ์žฌ์ •์˜ํ•˜๊ธฐ ์‰ฌ์›Œ ๋ณด์ด์ง€๋งŒ ๊ณณ๊ณณ์— ํ•จ์ •์ด ๋„์‚ฌ๋ฆฌ๊ณ  ์žˆ๋‹ค.

๋‹ค์Œ ์—ด๊ฑฐ ์ƒํ™ฉ ์ค‘ ํ•œ๊ฐ€์ง€๋ผ๋„ ํ•ด๋‹นํ•œ๋‹ค๋ฉด ์žฌ์ •์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

1. ๊ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ณธ์งˆ์ ์œผ๋กœ ๊ณ ์œ ํ•˜๋‹ค.

 - ๊ฐ’์„ ํ‘œํ˜„ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋™์ž‘ํ•˜๋Š” ๊ฐœ์ฒด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค

 - Thread๊ฐ€ ์ข‹์€ ์˜ˆ๋กœ, Object์˜ equals ๋ฉ”์„œ๋“œ๋Š” ์ด๋Ÿฌํ•œ ํด๋ž˜์Šค์— ๋”ฑ ๋งž๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

 

2. ์ธ์Šคํ„ด์Šค์˜ '๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ'์„ ๊ฒ€์‚ฌํ•  ์ผ์ด ์—†๋‹ค.

 - ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ์„ ์›ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์• ์ดˆ์— ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•  ๊ฒฝ์šฐ Object์˜ ๊ธฐ๋ณธ equals๋กœ๋งŒ ํ•ด๊ฒฐํ•œ๋‹ค.

 

3. ์ƒ์œ„ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•œ equals๊ฐ€ ํ•˜์œ„ ํด๋ž˜์Šค์—๋„ ๋”ฑ ๋“ค์–ด๋งž๋Š”๋‹ค.

 - ์˜ˆ๋กœ ๋Œ€๋ถ€๋ถ„์˜ Set ๊ตฌํ˜„์ฒด๋Š” AbstractSet์ด ๊ตฌํ˜„ํ•œ equals๋ฅผ ์ƒ์†๋ฐ›์•„ ์“ฐ๊ณ , List ๊ตฌํ˜„์ฒด๋“ค์€ AbstractList๋กœ๋ถ€ํ„ฐ, Map ๊ตฌํ˜„์ฒด๋“ค์€ AbstractMap์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์†๋ฐ›์•„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค.

 

4. ํด๋ž˜์Šค๊ฐ€ private์ด๊ฑฐ๋‚˜ package-private(default)์ด๊ณ  equals  ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ผ์ด ์—†๋‹ค.

 - ํ˜ธ์ถœํ•  ์ผ์ด ์—†๊ณ  ํ˜น์—ฌ๋‚˜ ์‹ค์ˆ˜๋กœ๋ผ๋„ equals๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•ด ๋‘์ž

public class NonEquals {
    @Override
    public boolean equals(Object obj) {
        throw new AssertionError();
    }
}

 

 ๊ทธ๋ ‡๋‹ค๋ฉด equals๋ฅผ ์žฌ์ •์˜ํ•ด์•ผ ํ•  ๋•Œ๋Š” ์–ธ์ œ์ธ๊ฐ€?

 

- ๊ฐ์ฒด ์‹๋ณ„์„ฑ(๋‘ ๊ฐ์ฒด๊ฐ€ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€๊ฐ€)์ด ์•„๋‹ˆ๋ผ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ์„ ํ™•์ธํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ƒ์œ„ ํด๋ž˜์Šค์˜ equals๊ฐ€ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ์„ ๋น„๊ตํ•˜๋„๋ก ์žฌ์ •์˜ ๋˜์ง€ ์•Š์•˜์„ ๋•Œ์ด๋‹ค. ์ฃผ๋กœ Integer์™€ String์ฒ˜๋Ÿผ ๊ฐ’์„ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค. ๋‘ ๊ฐ’ ๊ฐ์ฒด๋ฅผ equals๋กœ ๋น„๊ตํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ’์ด ๊ฐ™์€์ง€ ์•Œ๊ณ  ์‹ถ์–ด ํ•  ๊ฒƒ์ด๋‹ค.

 

 ๊ฐ’ ํด๋ž˜์Šค์—ฌ๋„ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋‘˜ ์ด์ƒ ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•˜๋Š” ์ธ์Šคํ„ด์Šค ํ†ต์ œ ํด๋ž˜์Šค(์•„์ดํ…œ 1)๋ผ๋ฉด equals๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. Enum(์•„์ดํ…œ 34)๋„ ์—ฌ๊ธฐ์— ํ•ด๋‹นํ•œ๋‹ค. ์ด๋Ÿฐ ํด๋ž˜์Šค์—์„œ๋Š” ์–ด์ฐจํ”ผ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๊ฐ€ 2๊ฐœ ์ด์ƒ ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์œผ๋‹ˆ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ๊ณผ ๊ฐ์ฒด ์‹๋ณ„์„ฑ์ด ์‚ฌ์‹ค์ƒ ๋˜‘๊ฐ™์€ ์˜๋ฏธ๊ฐ€ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ Object์˜ equals๊ฐ€ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ๊นŒ์ง€ ํ™•์ธํ•ด ์ค€๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

 equals ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ ํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ๋”ฐ๋ผ์•ผ ํ•œ๋‹ค. ๋‹ค์Œ์€ object ๋ช…์„ธ์— ์ ํžŒ ๊ทœ์•ฝ์ด๋‹ค.

 equals ๋ฉ”์„œ๋“œ๋Š” ๋™์น˜๊ด€๊ณ„๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉฐ, ๋‹ค์Œ์„ ๋งŒ์กฑํ•œ๋‹ค.

- ๋ฐ˜์‚ฌ์„ฑ(reflexivity) : null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x์— ๋Œ€ํ•ด, x.equals(x)๋Š” true๋‹ค.
- ๋Œ€์นญ์„ฑ(symmetry) : null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x,y์— ๋Œ€ํ•ด, x.equals(y) ๊ฐ€ true์ด๋ฉด y.equals(x)๋„ true ๋‹ค.
- ์ถ”์ด์„ฑ(transitivity) : null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x,y,z์— ๋Œ€ํ•ด, xequals(y)๊ฐ€ true์ด๊ณ  y.equals(z)๋„ true๋ฉด x.equals(z)๋„ true๋‹ค.
- ์ผ๊ด€์„ฑ(consistency) : null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ๊ฐ’ x,y์— ๋Œ€ํ•ด, x.equals(y)๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ํ˜ธ์ถœํ•˜๋ฉด ํ•ญ์ƒ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ํ•ญ์ƒ false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
- null-์•„๋‹˜ : null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x์— ๋Œ€ํ•ด, x.equals(null)์€ false ๋‹ค.

 

 

 ๋ชจ๋“  ๊ฐ์ฒด ์ง€ํ–ฅ ์–ธ์–ด์˜ ๋™์น˜ ๊ด€๊ณ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

- ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•ด ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ equals ๊ทœ์•ฝ์„ ๋งŒ์กฑ์‹œํ‚ฌ ๋ฐฉ๋ฒ•์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ฐ์ฒด ์ง€ํ–ฅ์  ์ถ”์ƒํ™”์˜ ์ด์ ์„ ํฌ๊ธฐํ•˜์ง€ ์•Š๋Š” ํ•œ์€ ๋ง์ด๋‹ค.

 ์ด ๋ง์€ ์–ผํ•, equals์•ˆ์˜ instanceof ๊ฒ€์‚ฌ๋ฅผ getClass ๊ฒ€์‚ฌ๋กœ ๋ฐ”๊พธ๋ฉด ๊ทœ์•ฝ๋„ ์ง€ํ‚ค๊ณ  ๊ฐ’๋„ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์œผ๋กœ ๋“ค๋ฆฐ๋‹ค.

 

 - ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™ ์œ„๋ฐฐ

public class Point {

    final int x;
    final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof Point))
            return false;
        Point p = (Point) obj;
        return p.x == x && p.y == y;
    }
}

public class CounterPoint extends Point {

    public CounterPoint(int x, int y) {
        super(x, y);
    }

    @Override
    public boolean equals(Object obj) {
    	// ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™ ์œ„๋ฐฐ
        if (obj == null || obj.getClass() != getClass())
            return false;
        Point p = (Point) obj;
        return p.x == x && p.y == y;
    }
}

 

 ๊ตฌ์ฒด ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ฐ’์„ ์ถ”๊ฐ€ํ•  ๋ฐฉ๋ฒ•์€ ์—†์ง€๋งŒ ๊ดœ์ฐฎ์€ ์šฐํšŒ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. '์ƒ์† ๋Œ€์‹  ์ปดํฌ์ง€์…˜์„ ์‚ฌ์šฉํ•˜๋ผ'๋Š” ์•„์ดํ…œ 18์˜ ์กฐ์–ธ์„ ๋”ฐ๋ฅด๋ฉด ๋œ๋‹ค.

 Point๋ฅผ ์ƒ์†ํ•˜๋Š” ๋Œ€์‹  Point๋ฅผ CounterPoint์˜ private ํ•„๋“œ๋กœ ๋‘๊ณ , CounterPoint์™€ ๊ฐ™์€ ์œ„์น˜์˜ ์ผ๋ฐ˜ Point๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ทฐ(view) ๋ฉ”์„œ๋“œ(์•„์ดํ…œ 6)๋ฅผ public์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ์‹์ด๋‹ค.

 

 - equals ๊ทœ์•ฝ์„ ์ง€ํ‚ค๋ฉฐ ๊ฐ’ ์ถ”๊ฐ€

 

public class CounterPoint {

    private final Point point;
    private final int x;
    private final int y;
    public CounterPoint(int x, int y) {
        this.x = x;
        this.y = y;
        point = new Point(x, y);
    }

    /**
     * Point ๋ทฐ ๋ฐ˜ํ™˜
     */
    public Point asPoint(){
        return point;
    }
    
    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof CounterPoint))
            return false;
        CounterPoint cp = (CounterPoint) obj;
        return cp.point.equals(point);
    }
}

 

 ํด๋ž˜์Šค๊ฐ€ ๋ถˆ๋ณ€์ด๋“  ๊ฐ€๋ณ€์ด๋“  equals ํŒ๋‹จ์— ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž์›์ด ๋ผ์–ด๋“ค๊ฒŒ ํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

์˜ˆ๋กœ java.net.URL์˜ equals๋Š” ์ฃผ์–ด์ง„ URL๊ณผ ๋งคํ•‘๋œ ํ˜ธ์ŠคํŠธ์˜ IP ์ฃผ์†Œ๋ฅผ ์ด์šฉํ•ด ๋น„๊ตํ•œ๋‹ค. ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์„ IP ์ฃผ์†Œ๋กœ ๋ฐ”๊พธ๋ ค๋ฉด ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ํ•ญ์ƒ ๊ฐ™๋‹ค๊ณ  ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. ์ด๋Š” URL์˜ equals๊ฐ€ ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ์–ด๊ธฐ๊ฒŒ ํ•˜๊ณ , ์‹ค๋ฌด์—์„œ๋„ ์ข…์ข… ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๋‹ค.

 

    public boolean equals(Object var1) {
        if (!(var1 instanceof URL)) {
            return false;
        } else {
            URL var2 = (URL)var1;
            return this.handler.equals(this, var2); // ๋ฌธ์ œ์ 
        }
    }
    
    // ๋ฌธ์ œ์ 
    protected boolean equals(URL var1, URL var2) {
        String var3 = var1.getRef();
        String var4 = var2.getRef();
        return (var3 == var4 || var3 != null && var3.equals(var4)) && this.sameFile(var1, var2);
    }

 ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๋ ค๋ฉด equals๋Š” ํ•ญ์‹œ ๋ฉ”๋ชจ๋ฆฌ์— ์กด์žฌํ•˜๋Š” ๊ฐ์ฒด๋งŒ์„ ์‚ฌ์šฉํ•œ ๊ฒฐ์ •์  ๊ณ„์‚ฐ๋งŒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

 

 ๋งˆ์ง€๋ง‰ ์š”๊ฑด์€ ๊ณต์‹ ์ด๋ฆ„์ด ์—†์œผ๋ฏ€๋กœ 'null-์•„๋‹˜'์œผ๋กœ ๋ถ€๋ฅธ๋‹ค.

์ด๋ฆ„์ฒ˜๋Ÿผ ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ null๊ณผ ๊ฐ™์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. ๋ช…์‹œ์  null ๊ฒ€์‚ฌ๋Š” ํ•„์š” ์—†๋‹ค.

    @Override
    public boolean equals(Object obj) {
        // ํ•„์š” ์—†๋‹ค.
        if(obj == null)
            return false;
        return super.equals(obj);
    }

 

 - ๋ฌต์‹œ์  Null ๊ฒ€์‚ฌ๋กœ instanceof ์—ฐ์‚ฐ์ž๋กœ ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์ธ์ง€ ๊ฒ€์‚ฌํ•˜์ž.

 

    @Override
    public boolean equals(Object obj) {
        // ๋ฌต์‹œ์  Null ๊ฒ€์‚ฌ
         if(!(obj instanceof MyType))
             return false;
         MyType myType = (MyType) obj;
        return super.equals(myType);
    }

 

 ์ง€๊ธˆ๊นŒ์ง€๋ฅผ ์ข…ํ•ฉํ•ด์„œ ์–‘์งˆ์˜ equals ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๋‹จ๊ณ„๋ณ„๋กœ ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

1. == ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด ์ž…๋ ฅ์ด ์ž๊ธฐ ์ž์‹ ์˜ ์ฐธ์กฐ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

 - ์ž๊ธฐ ์ž์‹ ์ด๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ. ๋‹จ์ˆœํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™”์šฉ์œผ๋กœ, ๋น„๊ต ์ž‘์—…์ด ๋ณต์žกํ•œ ์ƒํ™ฉ์ผ ๋•Œ ๊ฐ’์–ด์น˜๋ฅผ ํ•œ๋‹ค.

 

2. instanceof ์—ฐ์‚ฐ์ž๋กœ ์ž…๋ ฅ์ด ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์ธ์ง€ ํ™•์ธํ•œ๋‹ค. 

 - ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋•Œ์˜ ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์€ equals๊ฐ€ ์ •์˜๋œ ํด๋ž˜์Šค์ธ ๊ฒƒ์ด ๋ณดํ†ต์ด์ง€๋งŒ, ๊ฐ€๋” ๊ทธ ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„ํ•œ ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋  ์ˆ˜ ๋˜ ์žˆ๋‹ค. ์–ด๋–ค ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ž์‹ ์„ ๊ตฌํ˜„ํ•œ (์„œ๋กœ ๋‹ค๋ฅธ) ํด๋ž˜์Šค๋ผ๋ฆฌ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋„๋ก equals ๊ทœ์•ฝ์„ ์ˆ˜์ •ํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ์ด๋Ÿฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ผ๋ฉด equals์—์„œ (ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ) ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. Set, List, Map, Map.Entry ๋“ฑ์˜ ์ปฌ๋ ‰์…˜ ์ธํ„ฐํŽ˜์ด์Šค๋“ค์ด ์—ฌ๊ธฐ์— ํ•ด๋‹นํ•œ๋‹ค.

 

	public boolean equals(Object o) {
            if (!(o instanceof Map.Entry)) {
                return false;
            } else {
                Map.Entry<?, ?> e = (Map.Entry)o;
                // ๋‹ค๋ฅธ ๊ตฌํ˜„์ฒด ํ™•์ธ
                return AbstractMap.eq(this.key, e.getKey()) && AbstractMap.eq(this.value, e.getValue());
            }
        }

 

3. ์ž…๋ ฅ์„ ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์œผ๋กœ ํ˜•๋ณ€ํ™˜ํ•œ๋‹ค.

 - ์•ž์„  2๋ฒˆ์—์„œ instanceof ๊ฒ€์‚ฌ๋ฅผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋‹จ๊ณ„๋Š” 100% ์„ฑ๊ณตํ•œ๋‹ค.

 

4. ์ž…๋ ฅ ๊ฐ์ฒด์™€ ์ž๊ธฐ ์ž์‹ ์˜ ๋Œ€์‘๋˜๋Š” 'ํ•ต์‹ฌ'ํ•„๋“œ๋“ค์ด ๋ชจ๋‘ ์ผ์น˜ํ•˜๋Š”์ง€ ํ•˜๋‹ˆ์”ฉ ๊ฒ€์‚ฌํ•œ๋‹ค.

 - ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ์ผ์น˜ํ•˜๋ฉด true, ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅด๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 2๋‹จ๊ณ„์—์„œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์ž…๋ ฅ์˜ ํ•„๋“œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ๋„ ๊ทธ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ํƒ€์ž…์ด ํด๋ž˜์Šค๋ผ๋ฉด (์ ‘๊ทผ ๊ถŒํ•œ์— ๋”ฐ๋ผ) ํ•ด๋‹น ํ•„๋“œ์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

 ์–ด๋–ค ํ•„๋“œ๋ฅผ ๋จผ์ € ๋น„๊ตํ•˜๋Š๋ƒ๊ฐ€ equals์˜ ์„ฑ๋Šฅ์„ ์ขŒ์šฐํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ์ตœ์ƒ์˜ ์„ฑ๋Šฅ์„ ๋ฐ”๋ž€๋‹ค๋ฉด ๋‹ค๋ฅผ ๊ฐ€๋Šฅ์„ฑ์ด ๋” ํฌ๊ฑฐ๋‚˜ ๋น„๊ตํ•˜๋Š” ๋น„์šฉ์ด ์‹ผ ํ•„๋“œ๋ฅผ ๋น„๊ตํ•˜์ž. ๋™๊ธฐํ™”์šฉ ๋ฝ(lock) ํ•„๋“œ ๊ฐ™์ด ๊ฐ์ฒด์˜ ๋…ผ๋ฆฌ์  ์ƒํƒœ์™€ ๊ด€๋ จ ์—†๋Š” ํ•„๋“œ๋Š” ๋น„๊ตํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.

 

 equals๋ฅผ ๋‹ค ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด ์„ธ ๊ฐ€์ง€๋งŒ ์ž๋ฌธํ•ด ๋ณด์ž. ๋Œ€์นญ์ ์ธ๊ฐ€? ์ถ”์ด์„ฑ์ด ์žˆ๋Š”๊ฐ€? ์ผ๊ด€์ ์ธ๊ฐ€? 

 - ์ž๋ฌธ์—์„œ ๋๋‚ด์ง€ ๋ง๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด ๋Œ๋ ค๋ณด์ž. ๋‹จ, equals ๋ฉ”์„œ๋“œ๋ฅผ AutoValue(Google ํ”„๋ ˆ์ž„์›Œํฌ, ๋‹ค๋ฅธ ์˜ˆ๋กœ Lombok)๋ฅผ ์ด์šฉํ•ด ์ž‘์„ฑํ–ˆ๋‹ค๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ๋žตํ•ด๋„ ์•ˆ์‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก  ๋‚˜๋จธ์ง€ ์š”๊ฑด์ธ ๋ฐ˜์‚ฌ์„ฑ๊ณผ null-์•„๋‹˜๋„ ๋งŒ์กฑํ•ด์•ผ ํ•˜์ง€๋งŒ, ์ด ๋‘˜์ด ๋ฌธ์ œ ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ๋ณ„๋กœ ์—†๋‹ค.

 

public class PhoneNumber {
    private final short areaCode, prefix, lineNum;

    public PhoneNumber(int areaCode, int prefix, int lineNum){
        this.areaCode = rangeCheck(areaCode, 999, "์ง€์—ญ์ฝ”๋“œ");
        this.prefix = rangeCheck(prefix, 999, "ํ”„๋ฆฌํ”ฝ์Šค");
        this.lineNum = rangeCheck(lineNum, 9999, "๊ฐ€์ž…์ž ๋ฒˆํ˜ธ");
    }

    private static short rangeCheck(int val, int max, String arg){
        if(val < 0 || val > max)
            throw new IllegalArgumentException(arg + ": " + val);
        return (short) val;
    }

    @Override
    public boolean equals(Object o){
        if(o == this)
            return true;
        if(!(o instanceof PhoneNumber))
            return false;
        PhoneNumber pn = (PhoneNumber) o;
        return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode;
    }
}

 

 ๋งˆ์ง€๋ง‰ ์ฃผ์˜ ์‚ฌํ•ญ

 

1. equals๋ฅผ ์žฌ์ •์˜ ํ•  ๋• hashCode๋„ ๋ฐ˜๋“œ์‹œ ์žฌ์ •์˜ํ•˜์ž(์•„์ดํ…œ 11)

2. ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๋ ค ๋“ค์ง€ ๋ง์ž.

 - ํ•„๋“œ๋“ค์˜ ๋™์น˜์„ฑ๋งŒ ๊ฒ€์‚ฌํ•ด๋„ equals ๊ทœ์•ฝ์„ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. 

3. Object ์™ธ์˜ ํƒ€์ž…์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” equals ๋ฉ”์„œ๋“œ๋Š” ์„ ์–ธํ•˜์ง€ ๋ง์ž.

 - ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ equals๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•ด ๋†“๊ณ  ๋ฌธ์ œ์˜ ์›์ธ์„ ์ฐพ์•„ ํ—ค๋งจ๋‹ค.

 

    // ์ž…๋ ฅ ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ Object์—ฌ์•ผ ํ•œ๋‹ค., ์ปดํŒŒ์ผ ๋˜์ง€ ์•Š๋Š”๋‹ค.
    @Override
    public boolean equals(MyClass obj) {
    }

 

ํ•ต์‹ฌ ์ •๋ฆฌ

 ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ฉด equals๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ๋ง์ž. ๋งŽ์€ ๊ฒฝ์šฐ์— Object์˜ equals๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์ด ์›ํ•˜๋Š” ๋น„๊ต๋ฅผ ์ •ํ™•ํžˆ ์ˆ˜ํ–‰ํ•ด ์ค€๋‹ค. ์žฌ์ •์˜ํ•ด์•ผ ํ•  ๋•Œ๋Š” ๊ทธ ํด๋ž˜์Šค์˜ ํ•ต์‹ฌ ํ•„๋“œ ๋ชจ๋‘๋ฅผ ๋น ์ง์—†์ด, ๋‹ค์„ฏ ๊ฐ€์ง€ ๊ทœ์•ฝ์„ ํ™•์‹คํžˆ ์ง€์ผœ๊ฐ€๋ฉฐ ๋น„๊ตํ•ด์•ผ ํ•œ๋‹ค.

 

.์•„์ดํ…œ 11 - equals๋ฅผ ์žฌ์ •์˜ํ•˜๋ ค๊ฑฐ๋“  hashCode๋„ ์žฌ์ •์˜ํ•˜๋ผ

 

 equals๋ฅผ ์žฌ์ •์˜ํ•œ ํด๋ž˜์Šค ๋ชจ๋‘์—์„œ hashCode๋„ ์žฌ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.

- ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด hashCode ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ์–ด๊ธฐ๊ฒŒ ๋˜์–ด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ HashMap์ด๋‚˜ HashSet ๊ฐ™์€ ์ปฌ๋ ‰์…˜์˜ ์›์†Œ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๋‹ค. ๋‹ค์Œ์€ Object ๋ช…์„ธ์—์„œ ๋ฐœ์ทŒํ•œ ๊ทœ์•ฝ์ด๋‹ค.

 

 - equals ๋น„๊ต์— ์‚ฌ์šฉ๋˜๋Š” ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ๊ทธ ๊ฐ์ฒด์˜ hashCode ๋ฉ”์„œ๋“œ๋Š” ๋ช‡ ๋ฒˆ์„ ํ˜ธ์ถœํ•ด๋„ ์ผ๊ด€๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์žฌ์‹คํ–‰๋˜๋ฉด ๋‹ฌ๋ผ์ ธ๋„ ์ƒ๊ด€์—†๋‹ค.

 - equals(Object)๊ฐ€ ๋‘ ๊ฐ์ฒด๋ฅผ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค๋ฉด, ๋‘ ๊ฐ์ฒด์˜ hashCode๋Š” ๋˜‘๊ฐ™์€ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

 - equals(Object)๊ฐ€ ๋‘ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฅด๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋”๋ผ๋„, ๋‘ ๊ฐ์ฒด์˜ hashCode๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ํ•„์š”๋Š” ์—†๋‹ค. ๋‹จ, ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ด์‹œํ…Œ์ด๋ธ”์˜ ์„ฑ๋Šฅ์ด ์ข‹์•„์ง„๋‹ค.

 

 hashCode ์žฌ์ •์˜๋ฅผ ์ž˜๋ชปํ–ˆ์„ ๋•Œ ํฌ๊ฒŒ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ์กฐํ•ญ์ด ๋‘ ๋ฒˆ์งธ์ด๋‹ค. ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€ ๊ฐ์ฒด๋Š” ๊ฐ™์€ hashCode๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

 

        Map<PhoneNumber, String> m = new HashMap<>();
        // 1
        m.put(new PhoneNumber(707, 867, 5309), "์ œ๋‹ˆ");
        
        // 2
        m.get(new PhoneNumber(707, 867, 5309))

 ์œ„์˜ ์ฝ”๋“œ์—์„œ 1์„ ์‹คํ–‰ํ•œ ํ›„ 2๋ฅผ ์‹คํ–‰ํ•˜๋ฉด "์ œ๋‹ˆ"๊ฐ€ ๋‚˜์˜ค๊ธธ ๊ธฐ๋Œ€ํ•˜์ง€๋งŒ null ๊ฐ’์ด ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.

PhoneNumber ํด๋ž˜์Šค์—์„œ hashCode๋ฅผ ์žฌ์ •์˜ ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋…ผ๋ฆฌ์  ๋™์น˜์ธ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ hashCode๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋‘ ๋ฒˆ์งธ ๊ทœ์•ฝ์„ ์ง€ํ‚ค์ง€ ๋ชปํ–ˆ๋‹ค.

 

 ์•„๋ž˜์™€ ๊ฐ™์ด PhoneNumber ํด๋ž˜์Šค ์•ˆ์— equals์™€ hashCode๋ฅผ ๊ตฌํ˜„ํ•ด ์ฃผ๋ฉด ๊ธฐ๋Œ€ํ•œ ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

public class PhoneNumber {
    private final int areaCode;
    private final int prefix;
    private final int lineNum;

    public PhoneNumber(int areaCode, int prefix, int lineNum) {
        this.areaCode = areaCode;
        this.prefix = prefix;
        this.lineNum = lineNum;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PhoneNumber that = (PhoneNumber) o;
        return areaCode == that.areaCode && prefix == that.prefix && lineNum == that.lineNum;
    }

    @Override
    public int hashCode() {
        return Objects.hash(areaCode, prefix, lineNum);
    }

}

 

 ํ•ด์‹œ ์ถฉ๋Œ์ด ๋”์šฑ ์ ์€ ๋ฐฉ๋ฒ•์„ ์จ์•ผ ํ•œ๋‹ค๋ฉด ๊ตฌ์•„๋ฐ”์˜ com.google.common.hash.Hashing์„ ์ฐธ๊ณ ํ•˜์ž

 

 

 ํด๋ž˜์Šค๊ฐ€ ๋ถˆ๋ณ€์ด๊ณ  hashCode๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋น„์šฉ์ด ํฌ๋‹ค๋ฉด, ๋งค๋ฒˆ ์ƒˆ๋กœ ๊ณ„์‚ฐํ•˜๊ธฐ๋ณด๋‹ค๋Š” ์บ์‹ฑํ•˜๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

์ด ํƒ€์ž…์˜ ๊ฐ์ฒด๊ฐ€ ์ฃผ๋กœ ํ•ด์‹œ์˜ ํ‚ค๋กœ ์‚ฌ์šฉ๋  ๊ฒƒ ๊ฐ™๋‹ค๋ฉด ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์งˆ ๋•Œ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•ด ๋‘”๋‹ค.

 ํ•ด์‹œ ํ‚ค๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด hashCode๊ฐ€ ์ฒ˜์Œ ๋ถˆ๋ฆด ๋•Œ ๊ณ„์‚ฐํ•˜๋Š” ์ง€์—ฐ ์ดˆ๊ธฐํ™” ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–จ๊นŒ? ์ด๋Ÿฌํ•œ ์ง€์—ฐ ์ดˆ๊ธฐํ™” ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํด๋ž˜์Šค์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ค๋„๋ก ์‹ ๊ฒฝ ์จ์•ผ ํ•œ๋‹ค(์•„์ดํ…œ 83)

 

 ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

 

    private int hashCode; // ์ž๋™์œผ๋กœ 0์œผ๋กœ ์ดˆ๊ธฐํ™”
    public int hashCode2() {
        int result = hashCode;
        if(result == 0) {
            Integer.hashCode(areaCode);
            result = 31 * result + Integer.hashCode(prefix);
            result = 31 * result + Integer.hashCode(lineNum);
            hashCode = result;
        }
        return result;
    }

 

 ์„ฑ๋Šฅ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด hashCode ๊ณ„์‚ฐ์—์„œ ํ•ต์‹ฌ ํ•„๋“œ๋ฅผ ์ƒ๋žตํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.

- ์†๋„์•ผ ๋นจ๋ผ์ง€์ง€๋งŒ, hash ํ’ˆ์งˆ์ด ์ €ํ•˜๋˜์–ด hashTable์˜ ์„ฑ๋Šฅ์„ ์‹ฌ๊ฐํ•˜๊ฒŒ ๋–จ์–ด๋œจ๋ฆด ์ˆ˜ ์žˆ๋‹ค.

 

 hashCode๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์˜ ์ƒ์„ฑ ๊ทœ์น™์„ API ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž์„ธํžˆ ๊ณตํ‘œํ•˜์ง€ ๋ง์ž. ๊ทธ๋ž˜์•ผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ด ๊ฐ’์— ์˜์ง€ํ•˜์ง€ ์•Š๊ฒŒ ๋˜๊ณ , ์ถ”ํ›„์— ๊ณ„์‚ฐ ๋ฐฉ์‹์„ ๋ฐ”๊ฟ€ ์ˆ˜๋„ ์žˆ๋‹ค.

 

 

ํ•ต์‹ฌ ์ •๋ฆฌ

 equals๋ฅผ ์žฌ์ •์˜ํ•  ๋•Œ๋Š” hashCode๋„ ๋ฐ˜๋“œ์‹œ ์žฌ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์žฌ์ •์˜ํ•œ hashCode๋Š” Object์˜ API ๋ฌธ์„œ์— ๊ธฐ์ˆ ๋œ ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ๋”ฐ๋ผ์•ผ ํ•œ๋‹ค.

 

.์•„์ดํ…œ 12 - toString์„ ํ•ญ์ƒ ์žฌ์ •์˜ํ•˜๋ผ

 

 Object์˜ ๊ธฐ๋ณธ toString ๋ฉ”์„œ๋“œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ํด๋ž˜์Šค์— ์ ํ•ฉํ•œ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” PhoneNumber@adbbd ์ฒ˜๋Ÿผ ๋‹จ์ˆœํžˆ 'ํด๋ž˜์Šค_์ด๋ฆ„@16์ง„์ˆ˜๋กœํ‘œ์‹œํ•œHashCode'๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋ฟ์ด๋‹ค.

 toString์˜ ์ผ๋ฐ˜ ๊ทœ์•ฝ์— ๋”ฐ๋ฅด๋ฉด '๊ฐ„๊ฒฐํ•˜๋ฉด์„œ ์‚ฌ๋žŒ์ด ์ฝ๊ธฐ ์‰ฌ์šด ํ˜•ํƒœ์˜ ์œ ์ตํ•œ ์ •๋ณด'๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ '๋ชจ๋“  ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•˜๋ผ' ๋ผ๊ณ  ๊ทœ์•ฝ ๋˜์–ด์žˆ๋‹ค.

 toString์ด ์•ž์„  equals์™€ hashCode ๋งŒํผ ์ค‘์š”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ. toString์„ ์ž˜ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” ์‚ฌ์šฉํ•˜๊ธฐ์— ํ›จ์”ฌ ์ข‹๊ณ , ๋””๋ฒ„๊น… ๋˜ํ•œ ์‰ฝ๋‹ค. toString ๋ฉ”์„œ๋“œ๋Š” ๊ฐ์ฒด๋ฅผ println, printf, ๋ฌธ์ž์—ด ์—ฐ๊ฒฐ(+), assert ๊ตฌ๋ฌธ์— ๋„˜๊ธธ ๋•Œ, ํ˜น์€ ๋””๋ฒ„๊ฑฐ๊ฐ€ ๊ฐ์ฒด๋ฅผ ์ถœ๋ ฅํ•  ๋•Œ ์ž๋™์œผ๋กœ ๋ถˆ๋ฆฐ๋‹ค. ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„๋„ ์–ด๋””์„ ๊ฐ€ ์“ฐ์ด๊ฒŒ ๋œ๋‹ค.

 

 ์‹ค์ „์—์„œ toString์€ ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง„ ์ฃผ์š”ํ•œ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.

 

 toString์— ํฌ๋งท์„ ๋ช…์‹œํ•˜๋Š” ๊ฒŒ ํ•„์ˆ˜๋Š” ์•„๋‹ˆ์ง€๋งŒ ์˜๋„๋Š” ๋ช…ํ™•ํžˆ ๋ฐํ˜€์•ผ ํ•œ๋‹ค.

 

    /**
     * ํฐ ๋ฒˆํ˜ธ๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜
     * PhoneNumber{areaCode=82, prefix=10, lineNum=1234}
     */
    @Override
    public String toString() {
        return "PhoneNumber{" +
                "areaCode=" + areaCode +
                ", prefix=" + prefix +
                ", lineNum=" + lineNum +
                '}';
    }

 

 ํฌ๋งท ๋ช…์‹œ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด toString์ด ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์— ํฌํ•จ๋œ ์ •๋ณด๋ฅผ ์–ป์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š” APi๋ฅผ ์ œ๊ณตํ•˜์ž.

์˜ˆ๋กœ PhoneNumber ํด๋ž˜์Šจ๋Š ๊ฐ๊ฐ ์ง€์—ญ์ฝ”๋“œ, ํ”„๋ฆฌํ”ฝ์Šค, ๊ฐ€์ž…์ž ๋ฒˆํ˜ธ์šฉ ์ ‘๊ทผ์ž๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ด ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” toString์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ํŒŒ์‹ฑ ํ•  ์ˆ˜๋ฐ–์— ์—†๋‹ค.

 

 ์ •์  ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค(์•„์ดํ…œ 4)๋Š” toString์„ ์ œ๊ณตํ•  ์ด์œ ๊ฐ€ ์—†๋‹ค.. ๋˜ํ•œ, ๋Œ€๋ถ€๋ถ„์˜ ์—ด๊ฑฐ ํƒ€์ž…(์•„์ดํ…œ 34)๋„ ์ž๋ฐ”๊ฐ€ ์ด๋ฏธ ์™„๋ฒฝํ•œ toString์„ ์ œ๊ณตํ•˜์—ฌ ๋”ฐ๋กœ ์žฌ์ •์˜ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ํ•˜์ง€๋งŒ ํ•˜์œ„ ํด๋ž˜์Šค๋“ค์ด ๊ณต์œ ํ•ด์•ผ ํ•  ๋ฌธ์ž์—ด ํ‘œํ˜„์ด ์žˆ๋Š” ์ถ”์ƒ ํด๋ž˜์Šค๋ผ๋ฉด toString์„ ์žฌ์ •์˜ ํ•ด์ค˜์•ผ ํ•œ๋‹ค. ์˜ˆ๋กœ ๋Œ€๋‹ค์ˆ˜์˜ ์ปฌ๋ ‰์…˜ ๊ตฌํ˜„์ฒด๋Š” ์ถ”์ƒ ์ปฌ๋ ‰์…˜ ํด๋ž˜์Šค๋“ค์˜ toString ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†ํ•ด ์“ด๋‹ค.

 

 

 Object์˜ toString๋ณด๋‹ค๋Š” Lombok์ด๋‚˜ AutoValue์˜ ์ž๋™ ์ƒ์„ฑ toString์ด๋ผ๋„ ์‚ฌ์šฉํ•˜์ž.

 

ํ•ต์‹ฌ ์ •๋ฆฌ

 ๋ชจ๋“  ๊ตฌ์ฒด ํด๋ž˜์Šค์—์„œ Object์˜ toString์„ ์žฌ์ •์˜ํ•˜์ž. ์ƒ์œ„ ํด๋ž˜์Šค์—์„œ ์ด๋ฏธ ์•Œ๋งž๊ฒŒ ์žฌ์ •์˜ํ•œ ๊ฒฝ์šฐ๋Š” ์˜ˆ์™ธ๋‹ค.
toString์„ ์žฌ์ •์˜ํ•œ ํด๋ž˜์Šค๋Š” ์‚ฌ์šฉํ•˜๊ธฐ๋„ ์ฆ๊ฒ๊ณ  ๊ทธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์‹œ์Šคํ…œ์„ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ•ด ์ค€๋‹ค. toString์€ ํ•ด๋‹น ๊ฐ์ฒด์— ๊ด€ํ•œ ๋ช…ํ™•ํ•˜๊ณ  ์œ ์šฉํ•œ ์ •๋ณด๋ฅผ ์ฝ๊ธฐ ์ข‹์€ ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

 

.์•„์ดํ…œ 13 - clone ์žฌ์ •์˜๋Š” ์ฃผ์˜ํ•ด์„œ ์ง„ํ–‰ํ•˜๋ผ

 

 Cloneable์€ ๋ณต์ œํ•ด๋„ ๋˜๋Š” ํด๋ž˜์Šค์ž„์„ ๋ช…์‹œํ•˜๋Š” ์šฉ๋„์˜ ๋ฏน์Šค์ธ ์ธํ„ฐํŽ˜์ด์Šค(mixin interface, ์•„์ดํ…œ 20)์ง€๋งŒ Cloneable์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์™ธ๋ถ€ ๊ฐ์ฒด์—์„œ clone ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค. clone ๋ฉ”์„œ๋“œ๊ฐ€ ์„ ์–ธ๋œ ๊ณณ์ด Cloneable์ด ์•„๋‹Œ Object์ด๊ณ , ๊ทธ๋งˆ์ €๋„ protected๋ผ์„œ ์ด๋‹ค.

 

package java.lang;

public interface Cloneable {
}

  ๋ฉ”์„œ๋“œ ํ•˜๋‚˜ ์—†๋Š” Cloneable ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•˜๋Š” ์ผ์€ ๋ญ˜๊นŒ?

 - Object์˜ protected ๋ฉ”์„œ๋“œ์ธ clone์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•œ๋‹ค.

    //Object Class clone()

    @HotSpotIntrinsicCandidate
    protected native Object clone() throws CloneNotSupportedException;

 - Clonable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ clone์„ ํ˜ธ์ถœํ•˜๋ฉด ๊ทธ ๊ฐ์ฒด์˜ ํ•„๋“œ๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ณต์‚ฌํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค์—์„œ ํ˜ธ์ถœํ•˜๋ฉด 'CloneNotSupportedException'์„ ๋˜์ง„๋‹ค. 

 

 ์‹ค๋ฌด์—์„œ Cloneable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” clone ๋ฉ”์„œ๋“œ๋ฅผ public์œผ๋กœ ์ œ๊ณตํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž๋Š” ๋‹น์—ฐํžˆ ๋ณต์ œ๊ฐ€ ์ œ๋Œ€๋กœ ์ด๋ค„์ง€๋ฆฌ๋ผ ๊ธฐ๋Œ€ํ•œ๋‹ค. 

 

 clone ๋ฉ”์„œ๋“œ์˜ ์ผ๋ฐ˜ ๊ทœ์•ฝ์€ ํ—ˆ์ˆ ํ•˜๋‹ค. ๋‹ค์Œ์€ Object ๋ช…์„ธ์ด๋‹ค.

 

 ์ด ๊ฐ์ฒด์˜ ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•œ๋‹ค. '๋ณต์‚ฌ'์˜ ์ •ํ™•ํ•œ ๋œป์€ ๊ทธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

 1.x.clone() != x
 2.x.clone().getClass() == x.getClass()
 3.x.clone().equals(x) 

 ๊ด€๋ก€์ƒ ์œ„ ๋ฉ”์„œ๋“œ๋“ค์€ ์ฐธ์ด์ง€๋งŒ, ํ•„์ˆ˜๋Š” ์•„๋‹ˆ๋ฏ€๋กœ ๊ฐ•์ œ์„ฑ์ด ์—†๋‹ค.

 

 ์ฆ‰, clone ๋ฉ”์„œ๋“œ๊ฐ€ super.clone์ด ์•„๋‹Œ, ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•ด ์–ป์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋„ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋ถˆํ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ์ด ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ super.clone์„ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด ์ž˜๋ชป๋œ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ ธ ๊ฒฐ๊ตญ ํ•˜์œ„ ํด๋ž˜์Šค์˜ clone ๋ฉ”์„œ๋“œ๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค. 

public static void main(String[] args) throws CloneNotSupportedException {

        B b1 = new B();
        B b2 = new A();
        Object cloneB1 = b1.clone();
        Object cloneB2 = b2.clone(); 
        System.out.println(cloneB1.getClass()); // B
        System.out.println(cloneB2.getClass()); // A
        System.out.println(cloneB1.getClass() == cloneB2.getClass()); // false

    }

    static class B implements Cloneable {
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    static class A extends B implements Cloneable{
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

 clone์„ ์žฌ์ •์˜ํ•œ ํด๋ž˜์Šค๊ฐ€ final์ด๋ผ๋ฉด ๊ฑฑ์ •ํ•ด์•ผ ํ•  ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์—†์œผ๋‹ˆ ์ด ๊ด€๋ก€๋Š” ๋ฌด์‹œํ•ด๋„ ์•ˆ์ „ํ•˜๋‹ค. ํ•˜์ง€๋งŒ final ํด๋ž˜์Šค์˜ clone ๋ฉ”์„œ๋“œ๊ฐ€ super.clone์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด Cloneable์„ ๊ตฌํ˜„ํ•  ์ด์œ ๋„ ์—†๋‹ค. Object์˜ clone ๊ตฌํ˜„์˜ ๋™์ž‘ ๋ฐฉ์‹์— ๊ธฐ๋Œˆ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ๊ธฐ๋ณธ ํƒ€์ž…์ด๊ฑฐ๋‚˜ ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋ฉด ์ด ๊ฐ์ฒด๋Š” ์™„๋ฒฝํžˆ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์ƒํƒœ๋ผ ๋”  ์†๋ณผ ๊ณณ์ด ์—†๋‹ค.

์“ธ๋ฐ์—†๋Š” ๋ณต์‚ฌ๋ฅผ ์ง€์–‘ํ•œ๋‹ค๋Š” ๊ด€์ ์—์„œ ๋ณด๋ฉด ๋ถˆ๋ณ€ ํด๋ž˜์Šจ๋Š ๊ตณ์ด clone ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๊ฒŒ ์ข‹๋‹ค.

 

public class PhoneNumber implements Cloneable {

    private final short areaCode, prefix, lineNum;

    public PhoneNumber(short areaCode, short prefix, short lineNum) {
        this.areaCode = areaCode;
        this.prefix = prefix;
        this.lineNum = lineNum;
    }

    @Override
    public PhoneNumber clone() {
        try {
            return (PhoneNumber) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ๊ธฐ๋ณธ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— ์ผ์–ด๋‚  ์ˆ˜ ์—†๋Š” ์ผ์ด๋‹ค. or ๋ถˆ๋ณ€๊ฐ์ฒด์˜๊ฒฝ์šฐ
        }
    }
}

 ์žฌ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์€ ์ƒ์œ„ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•˜์œ„ ํƒ€์ž…์ผ ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฐฉ์‹์œผ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ˜•๋ณ€ํ™˜ ํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ฒŒ๋” ํ•ด์ฃผ์ž. ์ด๋ฅผ ์œ„ํ•ด ์•ž ์ฝ”๋“œ์—์„œ๋Š” super.clone์—์„œ ์–ป์€ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ์ „์— PhoneNumber๋กœ ํ˜•๋ณ€ํ™˜ํ•˜์˜€๋‹ค.

 

 super.clone์„ try-catch๋กœ ๊ฐ์‹ผ ์ด์œ ๋Š” Object์˜ clone ๋ฉ”์„œ๋“œ๊ฐ€ ๊ฒ€์‚ฌ ์˜ˆ์™ธ์ธ CloneNotSupportedExceptoin์„ ๋˜์ง€๋„๋ก ์„ ์–ธ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ์„ฑ๊ณตํ•  ๊ฒƒ์ž„์„ ์•Œ๊ณ  ์žˆ๋‹ค. ์‚ฌ์‹ค์€ ๋น„๊ฒ€์‚ฌ ์˜ˆ์™ธ์˜€๋‹ค๋Š” ์‹ ํ˜ธ๋‹ค(์•„์ดํ…œ 71)

 

 ๋‹ค์Œ์€ ๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ์ˆœ๊ฐ„์ด๋‹ค.

public class Stack implements Cloneable{
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e){
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop(){
        if(size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // ๋‹ค ์“ด ์ฐธ์กฐ ํ•ด์ œ
        return result;
    }

    /**
     * ์›์†Œ๋ฅผ ์œ„ํ•œ ๊ณต๊ฐ„์„ ์ ์–ด๋„ ํ•˜๋‚˜ ์ด์ƒ ํ™•๋ณดํ•œ๋‹ค.
     * ๋ฐฐ์—ด ํฌ๊ธฐ๋ฅผ ๋Š˜๋ ค์•ผ ํ•  ๋•Œ๋งˆ๋‹ค ๋Œ€๋žต ๋‘ ๋ฐฐ์”ฉ ๋Š˜๋ฆฐ๋‹ค.
     */
    private void ensureCapacity() {
        if (elements.length == size)
            elements = java.util.Arrays.copyOf(elements, 2 * size + 1);
    }

    @Override
    public Stack clone() {
        try {
            Stack result = (Stack) super.clone();
            result.elements = elements.clone();
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // ์ผ์–ด๋‚  ์ˆ˜ ์—†๋Š” ์ผ์ด๋‹ค.
        }
    }
}

 ๋งŒ์ผ ๋‹จ์ˆœํžˆ super.clone๊ฐ’์„ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋ฉด?

    @Override
    public Stack clone() {
        try {
            Stack clone = (Stack) super.clone();
            // TODO: copy mutable state here, so the clone can't change the internals of the original
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

 - size ํ•„๋“œ๋Š” ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์„ ๊ฐ–์ง€๋งŒ, elements ํ•„๋“œ๋Š” ์›๋ณธ Stack ์ธ์Šคํ„ด์Šค์™€ ๋˜‘๊ฐ™์€ ๋ฐฐ์—ด์„ ์ฐธ์กฐํ•  ๊ฒƒ์ด๋‹ค. ์›๋ณธ์ด๋‚˜ ๋ณต์ œ๋ณธ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋‹ค๋ฅธ ํ•˜๋‚˜๋„ ์ˆ˜์ •๋˜์–ด ๋ถˆ๋ณ€์‹์„ ํ•ด์น˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋กœ๊ทธ๋žจ์ด ์›ํ•˜๋Š” ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

 

 Stack ํด๋ž˜์Šค์˜ ํ•˜๋‚˜๋ฟ์ธ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•ž์„  ์ƒํ™ฉ์€ ์ ˆ๋Œ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. clone ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์‹ค์ƒ ์ƒ์„ฑ์ž์™€ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ธ๋‹ค. ์ฆ‰ , clone์€ ์›๋ณธ ๊ฐ์ฒด์— ์•„๋ฌด๋Ÿฐ ํ•ด๋ฅผ ๋ผ์น˜์ง€ ์•Š๋Š” ๋™์‹œ์— ๋ณต์ œ๋œ ๊ฐ์ฒด์˜ ๋ถˆ๋ณ€์‹์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด Stack์˜ clone ๋ฉ”์„œ๋“œ๋Š” ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜๋ ค๋ฉด ์Šคํƒ ๋‚ด๋ถ€ ์ •๋ณด๋ฅผ ๋ณต์‚ฌํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์œผ๋กœ elements ๋ฐฐ์—ด์˜ clone์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

 

   @Override
    public Stack clone() {
        try {
            Stack result = (Stack) super.clone();
            result.elements = elements.clone();
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // ์ผ์–ด๋‚  ์ˆ˜ ์—†๋Š” ์ผ์ด๋‹ค.
        }
    }

  ์œ„์˜ elements.clone() ์—์„œ Object[]๋กœ ํ˜•๋ณ€ํ™˜ํ•  ํ•„์š”๋Š” ์—†๋‹ค. ๋ฐฐ์—ด์˜ clone์€ ๋Ÿฐํƒ€์ž„ ํƒ€์ž…๊ณผ ์ปดํŒŒ์ผํƒ€์ž„ ํƒ€์ž… ๋ชจ๋‘๊ฐ€ ์›๋ณธ ๋ฐฐ์—ด๊ณผ ๋˜‘๊ฐ™์€ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐฐ์—ด์„ ๋ณต์ œํ•  ๋•Œ๋Š” ๋ฐฐ์—ด์˜ clone ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ๊ถŒ์žฅํ•œ๋‹ค. ์‚ฌ์‹ค, ๋ฐฐ์—ด์€ clone ๊ธฐ๋Šฅ์„ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ์œ ์ผํ•œ ์˜ˆ๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 ํ•œํŽธ, elements ํ•„๋“œ๊ฐ€ final์ด์—ˆ๋‹ค๋ฉด ์•ž์„œ์˜ ๋ฐฉ์‹์€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค. final ํ•„๋“œ์—๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—…์‹ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Š” ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ๋กœ, ์ง๋ ฌํ™”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Cloneable ์•„ํ‚คํ…์ฒ˜๋Š” '๊ฐ€๋ณ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ๋Š” final๋กœ ์„ ์–ธํ•˜๋ผ'๋Š” ์ผ๋ฐ˜ ์šฉ๋ฒ•๊ณผ ์ถฉ๋Œํ•œ๋‹ค.

 

 clone์„ ์žฌ๊ท€์  ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ๋•Œ๋„ ์žˆ๋‹ค. ํ•ด์‹œ ํ…Œ์ด๋ธ”์„ ์˜ˆ๋กœ ๋ณด๋ฉด ๋‚ด๋ถ€๋Š” ๋ฒ„ํ‚ท๋“ค์˜ ๋ฐฐ์—ด์ด๊ณ  ๋ฒ„ํ‚ท์€key-value๋กœ ์ด๋ฃจ์–ด์ง„ ์—”ํŠธ๋ฆฌ์ด๋‹ค. clone์„ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, Cloneable, Serializable {
    private transient Entry<?, ?>[] table;
    
    public synchronized Object clone() {
        Hashtable<?, ?> t = this.cloneHashtable();
        t.table = new Entry[this.table.length];

        for(int i = this.table.length; i-- > 0; t.table[i] = this.table[i] != null ? (Entry)this.table[i].clone() : null) {
        }

        t.keySet = null;
        t.entrySet = null;
        t.values = null;
        t.modCount = 0;
        return t;
    }
    
    private static class Entry<K, V> implements Map.Entry<K, V> {
        final int hash;
        final K key;
        V value;
        Entry<K, V> next;
    	protected Object clone() {
            return new Entry(this.hash, this.key, this.value, this.next == null ? null : (Entry)this.next.clone());
        }
    }
}

 

 ์•ž์„  stack ์ฒ˜๋Ÿผ elements(HashTable์˜ table)์„ ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ์ˆœํšŒํ•˜๋ฉฐ entry์˜ ๋ณต์‚ฌ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

 

 ์ƒ์„ฑ์ž์—์„œ๋Š” ์žฌ์ •์˜๋  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š”๋ฐ(์•„์ดํ…œ 19) clone ๋ฉ”์„œ๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. ๋งŒ์•ฝ clone์ด ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ํ•˜์œ„ ํด๋ž˜์Šค๋Š” ๋ณต์ œ ๊ณผ์ •์—์„œ ์ž์‹ ์˜ ์ƒํƒœ๋ฅผ ๊ต์ •ํ•  ๊ธฐํšŒ๋ฅผ ์žƒ๊ฒŒ ๋˜์–ด ์›๋ณธ๊ฐ€ ๋ณต์ œ๋ณธ์˜ ์ƒํƒœ๊ฐ€ ๋‹ฌ๋ผ์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋‹ค. 

 

 Object์˜ clone ๋ฉ”์„œ๋“œ๋Š” CloneNotSupportedException์„ ๋˜์ง„๋‹ค๊ณ  ์„ ์–ธํ–ˆ์ง€๋งŒ ์žฌ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค. public์ธ clone ๋ฉ”์„œ๋“œ์—์„œ๋Š” throws ์ ˆ์„ ์—†์• ์•ผ ํ•œ๋‹ค. ๊ฒ€์‚ฌ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š์•„์•ผ ๊ทธ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.(์•„์ดํ…œ 71)

 

 ์ƒ์†ํ•ด์„œ ์“ฐ๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค ์„ค๊ณ„ ๋ฐฉ์‹ ๋‘ ๊ฐ€์ง€(์•„์ดํ…œ 19) ์ค‘ ์–ด๋Š ์ชฝ์—์„œ๋“ , ์ƒ์†์šฉ ํด๋ž˜์Šค๋Š” Cloneable์„ ๊ตฌํ˜„ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. Object์˜ ๋ฐฉ์‹์„ ๋ชจ๋ฐฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š” clone ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด protected๋กœ ๋‘๊ณ  CloneNotSupportedException๋„ ๋˜์งˆ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ clone์„ ์žฌ์ •์˜ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ๋‹ค.

 

        @Override
        protected final Object clone() throws CloneNotSupportedException {
            return new CloneNotSupportedException();
        }

 

 Cloneable์„ ๊ตฌํ˜„ํ•œ ์Šค๋ ˆ๋“œ ์•ˆ์ „ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋Š” clone ๋ฉ”์„œ๋“œ ์—ญ์‹œ ์ ์ ˆํžˆ ๋™๊ธฐํ™”ํ•ด์ค˜์•ผ ํ•œ๋‹ค.(์•„์ดํ…œ 78)

Object์˜ clone๋ฉ”์„œ๋“œ๋Š” ๋™๊ธฐํ™”๋ฅผ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ super.clone ํ˜ธ์ถœ ์™ธ์— ๋‹ค๋ฅธ ํ•  ์ผ์ด ์—†๋”๋ผ๋„ clone์„ ์žฌ์ •์˜ํ•˜๊ณ  ๋™๊ธฐํ™”ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

 Cloneable์„ ์ด๋ฏธ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•œ๋‹ค๋ฉด ์–ด์ฉ” ์ˆ˜ ์—†์ด clone์„ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ๋Š” ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ๋กœ ๋” ๋‚˜์€ ๊ฐ์ฒด ๋ณต์‚ฌ ๋ฐฉ์‹์„ ํƒํ•œ๋‹ค.

    static class C {

        // ๋ณต์‚ฌ ์ƒ์„ฑ์ž
        public C(C c) {
            // ...
        }

        // ๋ณต์‚ฌ ํŒฉํ† ๋ฆฌ
        public static C newInstance(C c) {
            // ...
            return new C(c);
        }
    }

 

 ๋ณต์‚ฌ ์ƒ์„ฑ์ž, ๋ณต์‚ฌ ํŒฉํ„ฐ๋ฆฌ์˜ ๋” ์ •ํ™•ํ•œ ์ด๋ฆ„์€ ๋ณ€ํ™˜ ์ƒ์„ฑ์ž(conversion constructor)์™€ ๋ณ€ํ™˜ ํŒฉํ† ๋ฆฌ(conversion factory)์ด๋‹ค. ์ด๋“ค์„ ์ด์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ์›๋ณธ์˜ ๊ตฌํ˜„ ํƒ€์ž…์— ์–ฝ๋งค์ด์ง€ ์•Š๊ณ  ๋ณต์ œ๋ณธ์˜ ํƒ€์ž…์„ ์ง์ ‘ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋กœ HashSet์˜ ๊ฐ์ฒด s๋ฅผ TreeSet ํƒ€์ž…์œผ๋กœ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํ•ต์‹ฌ ์ •๋ฆฌ

 Cloneable์ด ๋ชฐ๊ณ  ์˜จ ๋ฌธ์ œ๋ฅผ ๋˜์งš์–ด ๋ดค์„ ๋•Œ, ์ƒˆ๋กœ์šด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ์ ˆ๋Œ€ Cloneable์„ ํ™•์žฅํ•ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ, ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋„ ์ด๋ฅผ ๊ตฌํ˜„ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. final ํด๋ž˜์Šค๋ผ๋ฉด Cloneable์„ ๊ตฌํ˜„ํ•ด๋„ ์œ„ํ—˜์ด ํฌ์ง€ ์•Š์ง€๋งŒ, ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ด€์ ์—์„œ ๊ฒ€ํ† ํ•œ ํ›„ ๋ณ„๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๋“œ๋ฌผ๊ฒŒ ํ˜€์šฉํ•ด์•ผ ํ•œ๋‹ค(์•„์ดํ…œ 67). ๊ธฐ๋ณธ ์›์น™์€ '๋ณต์ œ ๊ธฐ๋Šฅ์€ ์ƒ์„ฑ์ž์™€ ํŒฉํ„ฐ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒŒ ์ตœ๊ณ '๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ๋‹จ, ๋ฐฐ์—ด๋งŒ์€ clone ๋ฉ”์„œ๋“œ ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๊น”๋”ํ•œ, ์ด ๊ทœ์น™์˜ ํ•ฉ๋‹นํ•œ ์˜ˆ์™ธ๋‹ค.

 

.์•„์ดํ…œ 14 - Comparable์„ ๊ตฌํ˜„ํ• ์ง€ ๊ณ ๋ คํ•˜๋ผ.

 

public interface Comparable<T> {
    int compareTo(T var1);
}

 

 Comparable์˜ compareTo๋ฉ”์„œ๋“œ๋Š” ๋Š” ๋‹จ์ˆœ ๋™์น˜์„ฑ ๋น„๊ต์— ๋”ํ•ด ์ˆœ์„œ๊นŒ์ง€ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ œ๋„ค๋ฆญ ํ•˜๋‹ค.

Comparable์„ ๊ตฌํ˜„ํ–ˆ๋‹ค๋Š” ๊ฒƒ์€ ๊ทธ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋“ค์—๋Š” ์ž์—ฐ์ ์ธ ์ˆœ์„œ๊ฐ€ ์žˆ์Œ์„ ๋œปํ•œ๋‹ค.

 

 ์ž๋ฐ” ํ”Œ๋žซํผ ๋ผ์ด๋ฒ„๋ฆฌ๋“ค์˜ ๋ชจ๋“  ๊ฐ’ ํด๋ž˜์Šค์™€ ์—ด๊ฑฐ ํƒ€์ž…(์•„์ดํ…œ 34)์ด Comparable์„ ๊ตฌํ˜„ํ–ˆ๋‹ค. ์•ŒํŒŒ๋ฒณ, ์ˆซ์ž, ์—ฐ๋Œ€ ๊ฐ™์ด ์ˆœ์„œ๊ฐ€ ๋ช…ํ™•ํ•œ ๊ฐ’ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ Comparable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ž.

 

 compareTo ๋ฉ”์„œ๋“œ์˜ ์ผ๋ฐ˜ ๊ทœ์•ฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๊ณ  equals์˜ ๊ทœ์•ฝ๊ณผ ๋น„์Šทํ•˜๋‹ค.

 

์ด ๊ฐ์ฒด์™€ ์ฃผ์–ด์ง„ ๊ฐ์ฒด์˜ ์ˆœ์„œ๋ฅผ ๋น„๊ตํ•œ๋‹ค. ์ด ๊ฐ์ฒด๊ฐ€ ์ฃผ์–ด์ง„ ๊ฐ์ฒด๋ณด๋‹ค ์ž‘์„ ๊ฒฝ์šฐ ์Œ์˜ ์ •์ˆ˜, ๊ฐ™์œผ๋ฉด 0, ํฌ๋ฉด ์–‘์˜ ์ •์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด ๊ฐ์ฒด์™€ ๋น„๊ตํ•  ์ˆ˜ ์—†๋Š” ํƒ€์ž…์˜ ๊ฐ์ฒด๊ฐ€ ์ฃผ์–ด์ง€๋ฉด ClassCastException์„ ๋˜์ง„๋‹ค.
 ๋‹ค์Œ ์„ค๋ช…์—์„œ sgn(ํ‘œํ˜„์‹) ํ‘œ๊ธฐ๋Š” ์ˆ˜ํ•™์—์„œ ๋งํ•˜๋Š” ๋ถ€ํ˜ธ ํ•จ์ˆ˜(signum function)์„ ๋œปํ•˜๋ฉฐ, ํ‘œํ˜„์‹์˜ ๊ฐ’์ด ์Œ์ˆ˜, 0, ์–‘์ˆ˜ ์ผ ๋•Œ -1,0,1์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ •์˜ํ–ˆ๋‹ค.

 - Comparable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” ๋ชจ๋“  x,y์— ๋Œ€ํ•ด sgn(x.compareTo(y)) == -sgn(y.compareTo(x))์—ฌ์•ผ ํ•œ๋‹ค. (์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์—ญ์‹œ ๋™์ผ)
 - Comparable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” ์ถ”์ด์„ฑ์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, (x.compareTo(y) > 0 && y.compareTo(z) >0) ์ด๋ฉด x.compareTo(z) > 0์ด๋‹ค.
 - Comparable์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” ๋ชจ๋“  z์— ๋Œ€ํ•ด x.compareTo(y) == 0 ์ด๋ฉด sgn(x.compareTo(z) == sgn(y.compareTo(z)) ๋‹ค.
 - ๊ถŒ๊ณ ๊ฐ€ ํ•„์ˆ˜๋Š” ์•„๋‹ˆ์ง€๋งŒ ๊ผญ ์ง€ํ‚ฌ ์‚ฌํ•ญ์ด๋‹ค. (x.compareTo(y) == 0) == (x.equals(y)) ์—ฌ์•ผ ํ•œ๋‹ค. Comparable์„ ๊ตฌํ˜„ํ•˜๊ณ  ์ด ๊ถŒ๊ณ ๋ฅผ ์ง€ํ‚ค์ง€ ์•Š๋Š” ๋ชจ๋“  ํด๋ž˜์Šค๋Š” ๊ทธ ์‚ฌ์‹ค์„ ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช…์‹œํ•˜๋ฉด ์ ๋‹นํ•  ๊ฒƒ์ด๋‹ค. 
 *์ฃผ์˜: ์ดํด๋ž˜์Šค์˜ ์ˆœ์„œ๋Š” equals์˜ ๋ฉ”์„œ๋“œ์™€ ์ผ๊ด€๋˜์ง€ ์•Š๋‹ค

 

 ๋ชจ๋“  ๊ฐ์ฒด์— ๋Œ€ํ•ด ์ „์—ญ ๋™์น˜๊ด€๊ณ„๋ฅผ ๋ถ€์—ฌํ•˜๋Š” equals ๋ฉ”์„œ๋“œ์™€ ๋‹ฌ๋ฆฌ, compareTo๋Š” ํƒ€์ž…์ด ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ํƒ€์ž…์ด ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ฃผ์–ด์ง€๋ฉด ๊ฐ„๋‹จํžˆ ClassCastException์„ ๋˜์ ธ๋„ ๋˜๋ฉฐ, ๋Œ€๋ถ€๋ถ„ ๊ทธ๋ ‡๊ฒŒ ํ•œ๋‹ค. ๋ฌผ๋ก  ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งค๊ฐœ๋กœ ์ด๋ค„์กŒ์„ ๊ฒฝ์šฐ๋Š” ๋‹ค๋ฅธ ํƒ€์ž… ์‚ฌ์ด์˜ ๋น„๊ต๋„ ํ—ˆ์šฉ๋œ๋‹ค.

 hashCode ๊ทœ์•ฝ์„ ์ง€ํ‚ค์ง€ ๋ชปํ•˜๋ฉด ํ•ด์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์™€ ์–ด์šธ๋ฆฌ์ง€ ๋ชปํ•˜๋“ฏ,  compareTo ๊ทœ์•ฝ์„ ์ง€ํ‚ค์ง€ ๋ชปํ•˜๋ฉด ๋น„๊ต๋ฅผ ํ™œ์šฉํ•˜๋Š” ํด๋ž˜์Šค์™€ ์–ด์šธ๋ฆฌ์ง€ ๋ชปํ•œ๋‹ค. ์˜ˆ๋กœ TreeSet๊ณผ TreeMap, ๊ฒ€์ƒ‰๊ณผ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ํ™œ์šฉํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค์ธ Collections์™€ Arrays๊ฐ€ ์žˆ๋‹ค.

 compareTo์˜ ์ˆœ์„œ๊ฐ€ equals์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ผ๊ด€๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์—‡๋ฐ•์ž๊ฐ€ ๋‚  ์ˆ˜ ์žˆ๋Š” ๋ฐ ์˜ˆ๋กœ ์ปฌ๋ ‰์…˜ ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜๋œ ๋™์ž‘์—์„œ ์ด๋‹ค. ์ปฌ๋ ‰์…˜ ์ธํ„ฐํŽ˜์ด์Šค๋“ค์€ equals ๋ฉ”์„œ๋“œ์˜ ๊ทœ์•ฝ์„ ๋”ฐ๋ฅธ๋‹ค๊ณ  ๋˜์–ด ์žˆ์ง€๋งŒ, ์ •๋ ฌ๋œ ์ปฌ๋ ‰์…˜๋“ค์€ ๋™์น˜์„ฑ์„ ๋น„๊ตํ•  ๋•Œ equals ๋Œ€์‹  compareTo๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์•„์ฃผ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹ˆ์ง€๋งŒ, ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

 compareTo์™€ equals๊ฐ€ ์ผ๊ด€๋˜์ง€ ์•Š๋Š” BigDecimal ํด๋ž˜์Šค๋ฅผ ์˜ˆ๋กœ ์ƒ๊ฐํ•ด ๋ณด์ž. BigDecimal("1.0")๊ณผ BigDecimal("1.00")์€ equals๋ฉ”์†Œ๋“œ๋กœ ๋น„๊ตํ•˜๋ฉด ๋‹ค๋ฅด์ง€๋งŒ compareTo ๋ฉ”์†Œ๋“œ๋กœ ๋น„๊ตํ•˜๋ฉด ๋˜‘๊ฐ™๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ HashSet๊ณผ TreeSet์— ์‚ฝ์ž…ํ–ˆ์„ ๋•Œ ์›์†Œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค.

 

HashSet<BigDecimal> hashSet = new HashSet<>();
        TreeSet<BigDecimal> treeSet = new TreeSet<>();

        BigDecimal bigDecimal1 = new BigDecimal("1.0");
        BigDecimal bigDecimal2 = new BigDecimal("1.00");

        boolean compareTo = bigDecimal1.compareTo(bigDecimal2) == 0;

        boolean equals = bigDecimal1.equals(bigDecimal2);

        hashSet.add(bigDecimal1);
        hashSet.add(bigDecimal2);

        treeSet.add(bigDecimal1);
        treeSet.add(bigDecimal2);

        System.out.println(compareTo); // true
        System.out.println(equals); // false
        System.out.println(hashSet.size()); // 2
        System.out.println(treeSet.size()); // 1

 

 compreTo ๋ฉ”์„œ๋“œ๋Š” ๊ฐ ํ•„๋“œ๊ฐ€ ๋™์น˜์ธ์ง€๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ทธ ์ˆœ์„œ๋ฅผ ๋น„๊ตํ•œ๋‹ค. ๊ฐ์ฒด ์ฐธ์กฐ ํ•„๋“œ๋ฅผ ๋น„๊ตํ•˜๋ ค๋ฉด compreTo ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•œ๋‹ค. Comprable์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์€ ํ•„๋“œ๋‚˜ ํ‘œ์ค€์ด ์•„๋‹Œ ์ˆœ์„œ๋กœ ๋น„๊ตํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋น„๊ต์ž(Comprable)๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•œ๋‹ค. ๋น„๊ต์ž๋Š” ์ง์ ‘ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ž๋ฐ”๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ ์ค‘ ๊ณจ๋ผ ์“ฐ๋ฉด ๋œ๋‹ค. 

 ์•„๋ž˜๋Š” CaseInsensitivieString์ด Comprable<CaseInsensitivieString>์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ์œผ๋กœ CaseInsensitivieString ์ฐธ์กฐ์™€๋งŒ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค. Comparable์„ ๊ตฌํ˜„ํ•  ๋•Œ ์ผ๋ฐ˜์ ์œผ๋กœ ๋”ฐ๋ฅด๋Š” ํŒจํ„ด์ด๋‹ค.

public final class CaseInsensitiveString implements Comparable<CaseInsensitiveString>{

    private final String s;

    public CaseInsensitiveString(String s){
        if(s == null)
            throw new NullPointerException();
        this.s = s;
    }
    
    @Override
    public int compareTo(CaseInsensitiveString cis) {
        return String.CASE_INSENSITIVE_ORDER.compare(s, cis.s);
    }
}

 ์ฑ…์˜ 2ํŒ์—์„œ๋Š” ์ •์ˆ˜ ๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ๋ฅผ ๋น„๊ตํ•  ๋•Œ ๊ด€๊ณ„์—ฐ์‚ฐ์ž์ธ <์™€ >๋ฅผ, ์‹ค์ˆ˜ ๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ๋ฅผ ๋น„๊ตํ•  ๋•Œ๋Š” ์ •์  ๋ฉ”์„œ๋“œ์ธ Double.compre์™€ Float.compare ์‚ฌ์šฉ์„ ๊ถŒํ–ˆ์ง€๋งŒ ์ž๋ฐ” 7๋ถ€ํ„ฐ ๋ฐ•์‹ฑ ๋œ ๊ธฐ๋ณธ ํƒ€์ž… ํด๋ž˜์Šค๋“ค์— ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ์ •์  ๋ฉ”์†Œ๋“œ compre๋ฅผ ์ด์šฉํ•˜๋ฉด ๋˜๊ฒŒ ๋˜์—ˆ๋‹ค. compreTo ๋ฉ”์„œ๋“œ์—์„œ ๊ด€๊ณ„ ์—ฐ์‚ฐ์ž <์™€ >๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์ „ ๋ฐฉ์‹์€ ๊ฑฐ์ถ”์žฅ์Šค๋Ÿฝ๊ณ  ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•˜๋‹ˆ, ์ด์ œ๋Š” ์ถ”์ฒœํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 ์ž๋ฐ” 8์—์„œ๋Š” Comprator ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ผ๋ จ์˜ ๋น„๊ต์ž ์ƒ์„ฑ ๋ฉ”์„œ๋“œ(comparator construction method)์™€ ํŒ€์„ ๊พธ๋ ค ๋ฉ”์„œ๋“œ ์—ฐ์‡„ ๋ฐฉ์‹์œผ๋กœ ๋น„๊ต์ž๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. 

 

    @Override
    public int compareTo(PhoneNumber pn) {
        int result = Short.compare(areaCode, pn.areaCode);
        if(result == 0){
            result = Short.compare(prefix, pn.prefix);
            if(result == 0)
                result = Short.compare(lineNum, pn.lineNum);
        }
        return 0;
    }

 ์—์„œ ์ ์šฉํ•œ ๋ชจ์Šต์ด๋‹ค. ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋ณ€ํ•˜์ง€๋งŒ ๋‹ค์†Œ ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

    private static final Comparator<PhoneNumber> COMPARATOR =
            comparingInt((PhoneNumber pn) -> pn.areaCode)
            .thenComparingInt(pn -> pn.prefix)
            .thenComparingInt(pn -> pn.lineNum);

    @Override
    public int compareTo(PhoneNumber pn) {
        return COMPARATOR.compare(this, pn);
    }

 

 ์ด๋”ฐ๊ธˆ '๊ฐ’์˜ ์ฐจ'๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ๊ฐ’์ด ๋‘ ๋ฒˆ์งธ ๊ฐ’๋ณด๋‹ค ์ž‘์œผ๋ฉด ์Œ์ˆ˜๋ฅผ, ๋‘ ๊ฐ’์ด ๊ฐ™์œผ๋ฉด 0์„, ์ฒซ ๋ฒˆ์งธ ๊ฐ’์ด ํฌ๋ฉด ์–‘์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” compreTo๋‚˜ compre๋ฉ”์„œ๋“œ์™€ ๋งˆ์ฃผํ•  ๊ฒƒ์ด๋‹ค. ๋‹ค์Œ์ด ์˜ˆ์ด๋‹ค.

    static Comparator<Object> hashCodeOrder = new Comparator<>() {
        @Override
        public int compare(Object o1, Object o2) {
            return o1.hashCode() - o2.hashCode();
        }
    };

 ์ด ๋ฐฉ์‹์€ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. ์ •์ˆ˜ ์˜ค๋ฒ„ํ”Œ๋กœ๋ฅผ ์ผ์œผํ‚ค๊ฑฐ๋‚˜ IEEE 754 ๋ถ€๋™์†Œ์ˆ˜์  ๊ณ„์‚ฐ ๋ฐฉ์‹์— ๋”ฐ๋ฅธ ์˜ค๋ฅ˜๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.  ๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋‘ ๋ฐฉ์‹ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜์ž.

 

    static Comparator<Object> hashCodeOrder1 = new Comparator<>() {
        @Override
        public int compare(Object o1, Object o2) {
            return Integer.compare(o1.hashCode(), o2.hashCode());
        }        
    }; 
    // hashCodeOrder1 ์••์ถ• ์‹œ
    static Comparator<Object> hashCodeOrder1 = comparingInt(Object::hashCode);    
    
    static Comparator<Object> hashCodeOrder2 = Comparator.comparingInt(o -> o.hashCode());

 

ํ•ต์‹ฌ ์ •๋ฆฌ

 ์ˆœ์„œ๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๊ฐ’ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ๊ผญ Comprable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ, ๊ทธ ์ธ์Šคํ„ด์Šค๋“ค์„ ์‰ฝ๊ฒŒ ์ •๋ ฌํ•˜๊ณ , ๊ฒ€์ƒ‰ํ•˜๊ณ , ๋น„๊ต ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์ปฌ๋ ‰์…˜๊ณผ ์–ด์šฐ๋Ÿฌ์ง€๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค. compareTo ๋ฉ”์„œ๋“œ์—์„œ ํ•„๋“œ์˜ ๊ฐ’์„ ๋น„๊ตํ•  ๋•Œ <์™€ > ์—ฐ์‚ฐ์ž๋Š” ์“ฐ์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค. ๊ทธ ๋Œ€์‹  ๋ฐ•์‹ฑ๋œ ๊ธฐ๋ณธ ํƒ€์ž… ํด๋ž˜์Šค๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ •์  compre ๋ฉ”์„œ๋“œ๋‚˜ Comprator ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋น„๊ต์ž ์ƒ์„ฑ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ž.

๐Ÿ“ ๋Š๋‚€์ .

 equals, hashCode, toString, clone, compareTo ๋ฉ”์„œ๋“œ๋“ค์˜ ๊ทœ์•ฝ, ์žฌ์ •์˜๋ฅผ ์–ธ์ œ ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์•Œ ์ˆ˜ ์žˆ๋Š” ์žฅ์ด์˜€๋‹ค.
 ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ๋งŽ์ด ์ ‘ํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ์ด์—ˆ๋‹ค ๋ณด๋‹ˆ ์•ž์œผ๋กœ ์žฌ์ •์˜ํ•  ๋•Œ ์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.