Closed ForteEscape closed 2 months ago
우선 클래스에서는 구체 클래스와 추상 클래스가 존재합니다.
new
키워드로 객체 생성이 가능합니다.new
키워드로 객체 생성이 불가능합니다. 책 60페이지에서는 이렇게 말하고 있습니다.
추상 클래스의 하위 클래스에서라면
equals
규약을 지키면서도 값을 추가할 수 있다. (중략) 상위 클래스를 직접 인스턴스로 만드는 게 불가능하다면 지금까지 이야기한 문제들은 일어나지 않는다.
해당 문단을 이해하기 위해 책에서 언급한 예제와 추상 클래스를 상속받는 새로운 클래스를 구현하여 비교해봅시다.
public class TransitivityTest {
public enum Color { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
static 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;
}
}
static class ColorPoint extends Point {
private final Color color;
public ColorPoint (int x, int y, Color color) {
super(x, y);
this.color = color;
}
@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;
}
}
public static void main(String[] args) {
ColorPoint p1 = new ColorPoint(0, 0, Color.RED);
Point p2 = new Point(0, 0);
ColorPoint p3 = new ColorPoint(0, 0, Color.BLUE);
System.out.println(p1.equals(p2)); // true
System.out.println(p2.equals(p3)); // true
System.out.println(p3.equals(p1)); // false
}
}
/*
Point의 equals는 색을 무시하고, ColorPoint의 equals는 고려한다.
p1-p2, p2-p3의 비교에서는 색을 무시하였지만 p1-p3에는 고려하기 때문이다.
*/
위의 코드는 교재 내의 추이성 위배 사례로 언급된 코드입니다.
교재 58페이지에서 볼 수 있듯이, 구체 클래스를 확장해 새로운 값을 추가하면서 equals
규약을 만족할 방법은 존재하지 않습니다.
하지만 만약 Point
를 추상 클래스로 선언한다면 Point
의 객체는 생성할 수 없기 때문에 p2
는 생성할 수 없게 됩니다.
그렇다면 Point
를 상속받는 ColorPoint
나 SmellPoint
에서만 객체 생성을 할 수 있게 될 것이며, 그렇게 되면 동일 타입끼리의 equals
비교가 가능할 것입니다.
public class TransitivityTest {
public enum Color { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
public enum Smell { GOOD, BAD, SOSO }
static abstract class Point {
@Override
abstract public boolean equals(Object o); // 하위 클래스에서 무조건 구현해야 하는 함수
}
static class ColorPoint extends Point {
private final int x, y;
private final Color color;
public ColorPoint (int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ColorPoint)) // 동일 타입이 아닐 경우 false
return false;
if (((ColorPoint)o).x == this.x && ((ColorPoint)o).y == this.y && ((ColorPoint)o).color == this.color) {
return true;
}else {
return false;
}
}
}
static class SmellPoint extends Point {
private final int x, y;
private final Smell smell;
public SmellPoint (int x, int y, Smell smell) {
this.x = x;
this.y = y;
this.smell = smell;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof SmellPoint)) // 동일 타입이 아닐 경우 false
return false;
if (((SmellPoint)o).x == this.x && ((SmellPoint)o).y == this.y && ((SmellPoint)o).smell == this.smell) {
return true;
}else {
return false;
}
}
}
public static void main(String[] args) {
ColorPoint p1 = new ColorPoint(0, 0, Color.RED);
ColorPoint p2 = new ColorPoint(0, 0, Color.BLUE);
ColorPoint p3 = new ColorPoint(0, 0, Color.RED);
SmellPoint p4 = new SmellPoint(0, 0, Smell.GOOD);
System.out.println(p1.equals(p2)); // false
System.out.println(p1.equals(p3)); // true
System.out.println(p1.equals(p4)); // false
}
}
equals
메서드를 오버라이딩 하지 않는다면, 추상 클래스를 상속받는 하위 클래스를 생성조차 할 수 없게 됩니다.
그렇게 되면 하위 클래스들은 자신만의 equals
함수를 가지게 되고, 같은 타입일때만 동등성 비교를 하게 됩니다!
부모 클래스가 Abstract라 객체 인스턴스를 생성하지 못한다면 애초에 부모 클래스 타입과의 instanceof
연산을 할 필요가 없으니 부모 타입으로 생성된 인스턴스인 경우를 생각하지 않아도 되서 확장시켜도 해당 타입과의 비교만 수행하면 된다는 것으로 이해했습니다.
상세한 설명 감사드립니다! 혹시 제가 이해한 것이 다른 것이라면 이야기 해주시면 감사하겠습니다!
해당 지문이 잘 이해되지 않는데 상세한 설명이 가능한지 질문하고 싶습니다.