본문 바로가기

Java/Java

(JAVA) equals에 대해서(3)

 

Point의 x, y를 비교하는 equals 구현

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 obj) {

        if (! (obj instanceof Point)) {
            return false;
        }
        Point point = (Point) obj;

        return point.x == x && point.y == y;
    }
}

 

Point를 상속받는 ColorPrint

 

Point를 상속받고 ColorPrint의 equals를 재정의 하였다.

이때 색깔 정보를 무시할 수 없으므로 색깔 정보도 조건에 추가시킨다.

public class ColorPrint extends Point{
    private final Color color;

    public ColorPrint(int x, int y, Color color) {
        super(x, y);
        this.color = color;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof ColorPrint)) {
            return false;
        }

        return super.equals(obj) && ((ColorPrint) obj).color == color;
    }
}

Point는 x, y 정보만을 비교하고 ColorPrint는 x, y 정보 포함 color 즉 색깔 정보까지 포함해서 비교한다는 점에 주목하자.

 

실제 비교

public class Main {
    public static void main(String[] args) {
        Point point = new Point(1,2);
        ColorPrint colorPrint = new ColorPrint(1,2,Color.RED);

        boolean result = point.equals(colorPrint);
        System.out.println(result);

        boolean result2 = colorPrint.equals(point);
        System.out.println(result2);
    }
}

실행결과

point를 기준으로 colorPrint를 비교하였을 땐 true를 리턴하고 coloprint를 기준으로 point를 비교하였을 땐 false를 리턴한다.


추이성 위배

  • ColorPrint일 때는 색깔을 포함해서 비교
  • Point일 땐 색깔을 무시하고 비교
public class ColorPrint extends Point{
    private final Color color;

    public ColorPrint(int x, int y, Color color) {
        super(x, y);
        this.color = color;
    }

    @Override
    public boolean equals(Object obj) {

        if (!(obj instanceof Point))
            return false;
        
        // point이면 색상을 무시하고 비교 (Point의 객체가 들어올때 Point의 equals 사용)
        if (!(obj instanceof ColorPrint)) {
            System.out.println(this);
            return obj.equals(this);
        }
        // colorprint이면 색깔을 포함하여 비교
        return super.equals(obj) && ((ColorPrint) obj).color == color;
    }
}

실제 비교

 

  • point <=> colorprint1
  • colorprint1 <=> colorprint2
  • point <=> colorprint3
public class Main {
    public static void main(String[] args) {
        Point point = new Point(1,2);
        ColorPrint colorPrint1 = new ColorPrint(1,2,Color.RED);
        ColorPrint colorPrint2 = new ColorPrint(1,2,Color.BLUE);

        // TODO: [main] junwoochoi 08/02/2020 7:29 오후
        // point <=> colorPrint
        boolean result = point.equals(colorPrint1);
        System.out.println(result);

        // TODO: [main] junwoochoi 08/02/2020 7:30 오후
        // colorPrint <=> point
        boolean result4 = colorPrint1.equals(point);
        System.out.println(result4);

        // TODO: [main] junwoochoi 08/02/2020 7:30 오후
        // colorPrint <=> colorPrint
        boolean result2 = colorPrint1.equals(colorPrint2);
        System.out.println(result2);
    }
}

point의 equals는 Point 타입이 아니면 false를 리턴해버리기 때문에 추이 성에 위배된다.

실행결과


instance 검사를 getClass 검사로 변형


여기서 잠깐! getClass란? (궁금하신 분은 접기를 여세요)

더보기

해당 객체의 런타임 클래스를 리턴한다.

 

public class GetCassEx {

    public static void main(String[] args) {
        GetCassEx getCassEx = new GetCassEx();
        ClassA classA = getCassEx.new ExtendedClassA();
        classA.printThisClass();


    }
    public class ClassA {
        public void printThisClass () {
            System.out.println(getClass());
        }
    }
    public class ExtendedClassA extends ClassA {
        public void printClass() {
            printClass();
        }
    }

}

 

해당 코드에서 분명 ClassA에서 getClass() 메서드를 호출하였다. 하지만 출력되는 결과는 아래와 같다.

실행결과

ClassA에서 호출하였지만 런타임 시점의 객체는 ExtendedClassA 클래스이기 때문이다.


Point의 equals를 instance 비교가 아닌 getClass 비교로 변경

 

@Override
public boolean equals(Object obj) {
    Class<? extends Point> aClass = getClass();

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

    Point point = (Point) obj;

    return point.x == x && point.y == y;
}

 

Point point = new Point(1,2);
ColorPrint colorPrint1 = new ColorPrint(1,2,Color.RED);
ColorPrint colorPrint2 = new ColorPrint(1,2,Color.BLUE);

// TODO: [main] junwoochoi 08/02/2020 7:29 오후
// point <=> colorPrint
boolean result = point.equals(colorPrint1);
System.out.println(result);

// TODO: [main] junwoochoi 08/02/2020 7:30 오후
// colorPrint <=> point
boolean result4 = colorPrint1.equals(point);
System.out.println(result4);

// TODO: [main] junwoochoi 08/02/2020 7:30 오후
// colorPrint <=> colorPrint
boolean result2 = colorPrint1.equals(colorPrint2);
System.out.println(result2);

실행결과

 

모두 다 false가 리턴된 것을 볼 수 있다.

왜일까?

if (! (obj instanceof Point)) {
    return false;
}

이전의 결과는 false를 리턴하지 않는다. 하지만 getClass로 변경된 현재는 파라미터로 받은 객체와 현재 런타임 시점의 객체가 같아야 하기 때문에 false를 리턴한다.

ex) Point!= ColoPrint

같은 구현 클래스의 객체를 비교할 때만 True를 리턴 (Point <=> Point  ColorPrint <=> ColorPrint)

 


References

이펙티브 자바 Effective Java 3/E
국내도서
저자 : 조슈아 블로크(Joshua Bloch) / 이복연(개앞맵시)역
출판 : 인사이트 2018.11.01
상세보기

Code Link

https://github.com/mike6321/PURE_JAVA/tree/master/EffectiveStudy

 

mike6321/PURE_JAVA

Contribute to mike6321/PURE_JAVA development by creating an account on GitHub.

github.com

 

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

(JAVA) 비트연산(2)  (0) 2020.02.08
(JAVA) 비트연산(1)  (0) 2020.02.08
(JAVA) Exceptions in Java (2) - checked, unchecked  (0) 2020.02.04
(JAVA) Exceptions in Java (1)  (0) 2020.02.03
(JAVA) autoBoxing , unBoxing의 이해  (1) 2020.02.03