ITEM 10: The gerneral contract when overriding equlas

equals ๋ฉ”์„œ๋“œ์˜ ์žฌ์ •์˜์—๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํ•จ์ •์ด ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ๋Š” ์žฌ์ •์˜ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

  • ๊ฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ณธ์งˆ์ ์œผ๋กœ ๊ณ ์œ ํ•œ ๊ฒฝ์šฐ( ๋™์ž‘ํ•˜๋Š” ๊ฐœ์ฒด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ํด๋ž˜์Šค ex-Thread )

  • ์ธ์Šคํ„ด์Šค์˜ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ(logical equality)์„ ๊ฒ€์‚ฌํ•  ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ

  • ์ƒ์œ„ ํด๋ž˜์Šค์—์„œ ์žฌ์ •์˜ํ•œ equals๊ฐ€ ํ•˜์œ„ ํด๋ž˜์Šค์—๋„ ์ ํ•ฉํ•œ ๊ฒฝ์šฐ(AbstractSet, AbstractList)

  • ํด๋ž˜์Šค๊ฐ€ private or package-private์ด๊ณ  equals ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ

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

๊ฐ์ฒด ์‹๋ณ„์„ฑ(๋‘ ๊ฐ์ฒด๊ฐ€ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€์ง€)์ด ์•„๋‹ˆ๋ผ ๋…ผ๋ฆฌ์  ๋™์น˜์„ฑ(logical equality)์„ ํ™•์ธํ•ด์•ผํ•˜์ง€๋งŒ, ์ƒ์œ„ ํด๋ž˜์Šค์˜ equals๊ฐ€ ์žฌ์ •์˜๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์ด๋‹ค. ์ฃผ๋กœ, ๊ฐ’ ํด๋ž˜์Šค(Integer, String)๊ฐ€ ํ•ด๋‹น๋œ๋‹ค.

๊ฐ’ ํด๋ž˜์Šค์ด๋”๋ผ๋„ ์ •์  ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์†Œ๋“œ - item1๋ผ๋ฉด equals๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. (Enum ํฌํ•จ)

equals ๋ฉ”์„œ๋“œ ๊ทœ์•ฝ

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

๊ทœ์•ฝ

์„ค๋ช…

๋ฐ˜์‚ฌ์„ฑ(reflexivity)

null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x์— ๋Œ€ํ•ด, x.equals(x)๋Š” true์ด๋‹ค.

๋Œ€์น˜์„ฑ(symmetry)

null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x,y์— ๋Œ€ํ•ด, x.equals(y)๊ฐ€ true์ด๋ฉด, y.equals(x)๋„ true์ด๋‹ค.

์ถ”์ด์„ฑ(transitivity)

null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x, y, z์— ๋Œ€ํ•ด x.equals(y)๊ฐ€ true์ด๊ณ  y.equals(z)๊ฐ€ true์ด๋ฉด, x.eqauls(z)๋„ true์ด๋‹ค.

์ผ๊ด€์„ฑ(consistency)

null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x,y์— ๋Œ€ํ•ด x.equals(y)๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ํ˜ธ์ถœํ•˜๋ฉด ํ•ญ์ƒ true or flase๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

null ์•„๋‹˜

null์ด ์•„๋‹Œ ๋ชจ๋“  ์ฐธ์กฐ ๊ฐ’ x์— ๋Œ€ํ•ด, x.equals๋Š” flase์ด๋‹ค.

equals ๊ทœ์•ฝ์„ ์–ด๊ธฐ๋ฉด ๊ทธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์ด ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ• ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.

๋ฐ˜์‚ฌ์„ฑ

๋‹จ์ˆœํžˆ ๋งํ•˜๋ฉด ๊ฐ์ฒด๋Š” ์ž๊ธฐ ์ž์‹ ๊ณผ ๊ฐ™์•„์•ผ ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

๋Œ€์นญ์„ฑ

๋‘ ๊ฐ์ฒด๋Š” ์„œ๋กœ์— ๋Œ€ํ•œ ๋™์น˜์—ฌ๋ถ€์— ๋Œ€ํ•ด ๋˜‘๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™€์•ผํ•œ๋‹ค.

public final class CaseInsensitiveString {

    private final String s;

    public CaseInsensitiveString(String s){
        this.s = Objects.requireNonNull(s);
    }

    // ๋Œ€์นญ์„ฑ ์œ„๋ฐ˜
    @Override
    public boolean equals(Object o){
        if(o instanceof CaseInsensitiveString)
            return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
        if(o instanceof String)
            return s.equalsIgnoreCase((String) o);
        return false;
    }
}
CaseInsensitiveString cis = new CaseInsensitiveString("Test");
String s = "test";

System.out.println(s.equals(cis)); // false
System.out.println(cis.equals(s)); // true

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” String์˜ equals๋Š” CaseInsensitiveString์˜ ์กด์žฌ๋ฅผ ๋ชจ๋ฅด๊ธฐ๋•Œ๋ฌธ์— false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด๋Š” ๋Œ€์นญ์„ฑ์„ ์œ„๋ฐ˜ํ•œ๋‹ค.

equals ๊ทœ์•ฝ์„ ์–ด๊ธฐ๋ฉด, ๊ทธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค์ด ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ• ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด String๊ณผ์˜ ์—ฐ๋™์„ ํ•˜๊ฒ ๋‹ค๋Š” ๋ชฉํ‘œ๋ฅผ ๋ฒ„๋ ค์•ผํ•œ๋‹ค.

@Override
public boolean equals(Object o){
    return o instanceof CaseInsensitiveString && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}
CaseInsensitiveString cis = new CaseInsensitiveString("Test");
String s = "test";

System.out.println(s.equals(cis)); // false
System.out.println(cis.equals(s)); // false

์ถ”์ด์„ฑ

์ฒซ ๋ฒˆ์งธ ๊ฐ์ฒด์™€ ๋‘ ๋ฒˆ์งธ ๊ฐ์ฒด๊ฐ€ ๊ฐ™๊ณ , ๋‘ ๋ฒˆ์งธ ๊ฐ์ฒด์™€ ์„ธ ๋ฒˆ์งธ ๊ฐ์ฒด๊ฐ€ ๊ฐ™๋‹ค๋ฉด, ์ฒซ๋ฒˆ์งธ ๊ฐ์ฒด์™€ ์„ธ๋ฒˆ์งธ ๊ฐ์ฒด๋„ ๊ฐ™์•„์•ผํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

public class Point {

    private final int x;
    private final int y;

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

    @Override
    public boolean equals(Object o){
        if(!(o instanceof Point))
            return false;
        Point p = (Point)o;
        return p.x == x && p.y == y;
    }
}
public class ColorPoint extends Point{
    private final String color;

    public ColorPoint(int x, int y, String color){
        super(x,y);
        this.color = color;
    }
}

ColorPoint ํด๋ž˜์Šค์—์„œ equals ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, Point equals๊ฐ€ ์ƒ์†๋˜์–ด ์ƒ‰์ƒ ์ •๋ณด๋Š” ๋ฌด์‹œ๋œ ์ฑ„ ๋น„๊ต๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ๋œ๋‹ค. ์ด๋•Œ, ๊ทœ์•ฝ์€ ์–ด๊ธด ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์ค‘์š”ํ•œ ์ •๋ณด๋ฅผ ๋†“์น˜๊ฒŒ ๋˜๋ฏ€๋กœ ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์—†๋‹ค.

@Override
public boolean equals(Object o){
    if(!(o instanceof ColorPoint))
        return false;
    return super.equals(o) && ((ColorPoint) o).color == color;
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด equals๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด Point์™€ ColorPoint๋ฅผ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ์™€ ๊ทธ ๋‘˜์„ ๋ฐ”๊ฟ”์„œ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ( ๋Œ€์นญ์„ฑ ์œ„๋ฐฐ )

Point p = new Point(1,2);
ColorPoint cp = new ColorPoint(1,2, Color.RED);

System.out.println(p.equals(cp)); // true
System.out.println(cp.equals(p)); // false

์šฐ์„  p.equals(cp) ๋Š” ์ƒ‰์ƒ ์ •๋ณด์— ๋Œ€ํ•œ ๋น„๊ต๋Š” ๋ฌด์‹œํ•˜๊ณ , cp.equals(p)๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํด๋ž˜์Šค ์ข…๋ฅ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค๋ฉฐ ๋งค๋ฒˆ false๋งŒ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋‹ค.

    @Override
    public boolean equals(Object o){
        if(!(o instanceof Point))
            return false;
        if(!(o instanceof ColorPoint))
            return o.equals(this);
        return super.equals(o) && ((ColorPoint) o).color == color;
    }
Point p = new Point(1,2);
ColorPoint cp = new ColorPoint(1,2, Color.RED);
ColorPoint cp2 = new ColorPoint(1,2,Color.BLACK);

System.out.println(cp.equals(p)); // true
System.out.println(p.equals(cp2)); // true 
System.out.println(cp2.equals(cp)); // false

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

equals ์•ˆ์˜ instance ๊ฒ€์‚ฌ๋ฅผ getClass ๊ฒ€์‚ฌ๋กœ ๋ฐ”๊พธ๋ฉด ๊ทœ์•ฝ๋„ ์ง€ํ‚ค๋ฉด์„œ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋Š” ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™์— ์œ„๋ฐ˜๋œ๋‹ค. ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™์— ๋”ฐ๋ฅด๋ฉด, ์–ด๋–ค ํƒ€์ž…์— ์žˆ์–ด ์ค‘์š”ํ•œ ์†์„ฑ์ด๋ผ๋ฉด, ๊ทธ ํ•˜์œ„ ํƒ€์ž…์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ค‘์š”ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ ํƒ€์ž…์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ํ•˜์œ„ ํƒ€์ž…์—์„œ๋„ ๋˜‘๊ฐ™์ด ์ž˜ ๋™์ž‘ํ•ด์•ผํ•œ๋‹ค.

๊ตฌ์ฒด ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ฐ’์„ ์ถ”๊ฐ€ํ•  ๋ฐฉ๋ฒ•์€ ์—†์ง€๋งŒ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ํ•˜๋‚˜์žˆ๋‹ค. [์ƒ์†๋Œ€์‹  ์ปดํฌ์ง€์…˜์„ ์‚ฌ์šฉํ•ด๋ผ - Item18]

public class ColorPoint {
    private final Color color;
    private final Point point;

    public ColorPoint(int x, int y, Color color){
        this.point = new Point(x,y);
        this.color = Objects.requireNonNull(color);
    }

    public Point asPoint(){
        return point;
    }

    @Override
    public boolean equals(Object o){
        if(!(o instanceof ColorPoint))
            return false;
        ColorPoint cp = (ColorPoint) o;
        return cp.point.equals(point) && cp.color.equals(cp);
    }

}
Point p = new Point(1,2);
ColorPoint cp = new ColorPoint(1,2, Color.RED);
ColorPoint cp2 = new ColorPoint(1,2,Color.BLACK);

System.out.println(cp.equals(p)); // false
System.out.println(p.equals(cp2)); // false 
System.out.println(cp2.equals(cp)); // false

Point ๋ฅผ ์ƒ์†ํ•˜๋Š” ๋Œ€์‹  Point๋ฅผ ColorPoint์˜ private ํ•„๋“œ๋กœ ๋‘๊ณ , ColorPoint์™€ ๊ฐ™์€ ์œ„์น˜์˜ ์ผ๋ฐ˜ Point๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ทฐ๋ฅผ public์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋„ ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•ด ๊ฐ’์„ ์ถ”๊ฐ€ํ•œ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค.

public class Timestamp extends java.util.Date {

    /**
     * @serial
     */
    private int nanos;

  ...
}

Timestamp๋Š” Date๋ฅผ ์ƒ์†๋ฐ›์€ ํ›„ nanos ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ Timestamp์˜ equals๋Š” ๋Œ€์นญ์„ฑ์„ ์œ„๋ฐฐํ•ด, Date ๊ฐ์ฒด์™€ ํ•œ ์ปฌ๋ ‰์…˜์— ๋„ฃ๊ฑฐ๋‚˜ ์„œ๋กœ ์„ž์–ด ์‚ฌ์šฉํ•˜๋ฉด, ์—‰๋šฑํ•˜๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. Timestamp์˜ API ์„ค๋ช…์— ์ฃผ์˜์‚ฌํ•ญ์„ ์–ธ๊ธ‰ํ•˜๊ณ  ์žˆ๋‹ค.

์ผ๊ด€์„ฑ

๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™๋‹ค๋ฉด ์–ด๋Š ํ•˜๋‚˜ ํ˜น์€ ๋‘ ๊ฐ์ฒด๊ฐ€ ์ˆ˜์ •๋˜์ง€ ์•Š๋Š” ํ•œ ์•ž์œผ๋กœ๋„ ์˜์›ํžˆ ๊ฐ™์•„์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ๊ฐ€๋ณ€ ๊ฐ์ฒด๋Š” ๋น„๊ต ์‹œ์ ์— ๋”ฐ๋ผ ์„œ๋กœ ๋‹ค๋ฅผ ์ˆ˜๋„ ๊ฐ™์„ ์ˆ˜๋„ ์žˆ๋Š” ๋ฐ˜๋ฉด, ๋ถˆ๋ณ€ ๊ฐ์ฒด๋Š” ํ•œ๋ฒˆ ๋‹ค๋ฅด๋ฉด ๋๊นŒ์ง€ ๋‹ฌ๋ผ์•ผํ•œ๋‹ค. ์ฆ‰, ๋ถˆ๋ณ€ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ๋กœ ํ–ˆ๋‹ค๋ฉด eqauls๋Š” ํ•œ๋ฒˆ ๊ฐ™๋‹ค๊ณ  ํ•œ ๊ฐ์ฒด์™€ ์˜์›ํžˆ ๊ฐ™๊ณ , ํ•œ๋ฒˆ ๋‹ค๋ฅธ ๊ฐ์ฒด์™€๋Š” ์˜์›ํžˆ ๋‹ค๋ฅด๋„๋ก ๋งŒ๋“ค์–ด์•ผํ•œ๋‹ค.

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

NULL-์•„๋‹˜

๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ null๊ณผ ๊ฐ™์ง€ ์•Š์•„์•ผํ•œ๋‹ค. ์‹ค์ˆ˜๋กœ NullPointException์„ ๋˜์ง€๋Š” ์ฝ”๋“œ๋Š” ํ”ํ•  ๊ฒƒ์ด์ง€๋งŒ, ์ด ๊ทœ์•ฝ์€ ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๋„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋™์น˜์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๋ ค๋ฉด equals๋Š” ๊ฐ์ฒด๋ฅผ ์ ์ ˆํžˆ ํ˜•๋ณ€ํ™˜ํ•œ ํ›„ ํ•„์ˆ˜ ํ•„๋“œ๋“ค์˜ ๊ฐ’์„ ์•Œ์•„์•ผํ•˜๋Š”๋ฐ, ์ด๋•Œ ํ˜•๋ณ€ํ™˜์— ์•ž์„œ instanceof ์—ฐ์‚ฐ์ž๋กœ ์ž…๋ ฅ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํƒ€์ž…์ธ์ง€ ๊ฒ€์‚ฌํ•ด์•ผํ•œ๋‹ค. instanceof์˜ ์ฒซ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž๊ฐ€ null์ด๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๋ฌต์‹œ์ ์ธ null๊ฒ€์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

    @Override
    public boolean equals(Object o){
        if(!(o instanseof MyType))
            return false;
        MyType mt = (Mytype) o;

equals ๊ตฌํ˜„ ์ฃผ์˜ ์‚ฌํ•ญ

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

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

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

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

์ด๋•Œ, float, double์„ ์ œ์™ธํ•œ ๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ๋Š” ==๋กœ ๋น„๊ตํ•˜๊ณ , ์ฐธ์กฐ ํƒ€์ž… ํ•„๋“œ๋Š” ๊ฐ๊ฐ์˜ equals ๋ฉ”์„œ๋“œ๋กœ, float, double์€ Float.compare(float, float)์™€ Double.compare(double,double)๋กœ ๋น„๊ตํ•œ๋‹ค. Float.equals์™€ Double.equals๋Š” ์˜คํ† ๋ฐ•์‹ฑ์„ ์ˆ˜๋ฐ˜ํ•  ์ˆ˜ ์žˆ์–ด ์„ฑ๋Šฅ์ƒ ์ข‹์ง€ ์•Š๋‹ค.

๋•Œ๋กœ๋Š” null๊ฐ’๋„ ์ •์ƒ ๊ฐ’์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ์ฐธ์กฐ ํƒ€์ž… ํ•„๋“œ๋„ ์žˆ๋Š”๋ฐ, ์ด๋•Œ๋Š” Objects.equals(Object, Object)๋กœ ๋น„๊ตํ•ด NullPointerException์„ ์˜ˆ๋ฐฉํ•ด์•ผํ•œ๋‹ค.

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

  • equals๋ฅผ ์žฌ์ •์˜ํ•  ๋•Œ๋Š” hashCode๋„ ๋ฐ˜๋“œ์‹œ ์žฌ์ •์˜ ํ•ด์•ผํ•œ๋‹ค.(item 11)

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

AutoValue ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด equals์™€ hashCode๋ฅผ ์ž‘์„ฑํ•ด์ค€๋‹ค. (AutoValue ์˜ˆ์ œ ๋ณด๊ธฐ)

@AutoValue

<dependencies>
    <dependency>
        <groupId>com.google.auto.value</groupId>
        <artifactId>auto-value</artifactId>
        <version>1.3</version>
    </dependency>
</dependencies>
import com.google.auto.value.AutoValue;

@AutoValue
public abstract class Product {

    public abstract String name();
    public abstract String price();

    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder name(String name);
        public abstract Builder price(String price);
        public abstract Product build();
    }

    public static Product.Builder builder() {
        return new AutoValue_Product.Builder();
    }
}

Last updated