클래스 계승 관계에서 equals 방법을 실현하는 세부 사항

5268 단어 equals

equals 방법


책에 따르면 두 대상이 같은지 비교하려면 equals ()와hashCode () 두 가지 방법을 정의해야 한다.equals 방법의 전체 서명은 다음과 같습니다: equals (Object o).equals 방법을 정의하는 절차는 다음과 같습니다.
1. 들어오는 대상이 비어 있는지 비교하고, 비어 있으면false로 돌아간다.
2. 들어오는 대상의 유형이 같은지 비교하고 다르면false로 되돌아간다.
3. 정의된 대상에 따라 각 필드가 같은지 비교하고 같지 않으면false로 돌아간다.
 
우리는 equals() 방법이 전달과 교환이 가능한 대등한 관계를 의미한다는 것을 알고 있다. 즉, A.equals(B)의 결과가true라면 B.equals(A)의 결과도true이다.
클래스 계승 관계를 도입했을 때 자류가 같은 방법을 정의해야 할 때 부류의 방법을 다시 사용하고 자신의 부분만 수정할 수 있다.그러나 조금 부주의한 상태에서 앞의 이런 가정을 깨뜨릴 수도 있다.

계승 관계의 실현


hashCode 방법을 고려하지 않은 상태에서 다음은 부모 클래스와 하위 클래스를 포함하는 equals 구현이다.
 
class BaseClass
{
    private int x;

    public BaseClass(int i)
    {
        x = i;
    }

    public boolean equals(Object rhs)
    {
        if(!(rhs instanceof rhs))
            return false;

        return x == ((BaseClass)rhs).x;
    }
}

class DerivedClass extends BaseClass
{
    private int y;

    public DerivedClass(int i, int j)
    {
        super(i);
        y = j;
    }

    public boolean equals(Object rhs)
    {
        if(!(rhs instanceof DerivedClass))
            return false;

        return super.equals(rhs) &&
            y == ((DerivedClass)rhs).y;
    }
}

public class EqualsWithInheritance
{
    public static void main(String[] args)
    {
        BaseClass a = new BaseClass(5);
        DerivedClass b = new DerivedClass(5, 8);
        DerivedClass c = new DerivedClass(5, 8);

        System.out.println("b.equals(c): " + b.equals(c));
        System.out.println("a.equals(b): " + a.equals(b));
        System.out.println("b.equals(a): " + b.equals(a));
    }
}

 
위 코드를 실행하면 다음과 같은 이상한 결과가 표시됩니다.
 
b.equals(c): true
a.equals(b): true
b.equals(a): false

 
우리 앞에 a.equals(b)가true인 이상 왜 뒤에 b.equals(a)의 결과가 오히려false가 되었을까?이러한 실현에는 틀림없이 문제가 있을 것이다. 분명히 이것은 equals ()의 대등성을 깨뜨렸다.

문제 분석


만약 우리가 앞의 코드가 실현되는 것을 자세히 보면, 문제가 부류와 자류가 정의한 equals () 방법에 나타날 가능성이 높다는 것을 발견할 수 있다.부류에서 정의된 equals 방법은 부류에서도 정의되었다.그래서 우리가 a.equals(b)를 호출할 때 a는 부류가 만든 대상이기 때문에 부류의 equals 방법을 실행하고 b는 부류의 실례화 대상이며 b.equals(a)는 부류의 equals 방법을 실행한다.
또 다른 문제는 instanceof다.자바에서 instanceof는 왼쪽 대상이 오른쪽 클래스인지 테스트하는 실례를 나타냅니다.클래스의 계승 관계로 인해 우리는 하위 클래스도 부류의 실례라고 말할 수 있다.예를 들어 자바에서 모든 대상은 Object에서 계승된다. 그러면 우리가 임의로 정의한 클래스의 실례 대상이 instanceof Object를 호출하여 되돌아오는 결과는true이다.그래서 문제의 근원은 바로 이 인스타그램에 있다.
다시 한 번 우리의 이 문제를 보면 우리 자체의 논리적 요구는 부류의 실례와 부류의 실례가 다르기 때문에 a.equals(b)와 b.equals(a)는 모두false로 돌아가야 한다.그렇다면 지금 문제는 우리가 어떤 방법으로 부류와 자류가 다른 유형을 비교해야 하는가 하는 것이다.문서를 검토한 후에 getClass () 방법을 사용할 수 있습니다.이 방법은 대상이 실행될 때class를 되돌려줍니다.jvm 가상 기기에서 모든 종류의 상세한 유형 정보는 방법 구역에 정의되고 여러 라인에 공유된다는 것을 우리는 알고 있다.여기에는 각 클래스의 상세한 차이를 포함할 것이다. 예를 들어 b는 클래스DerivedClass의 실례화된 대상이기 때문에 그들의 구분을 실현할 수 있다.
수정된 구현 코드는 다음과 같습니다.
 
class BaseClass
{
    private int x;

    public BaseClass(int i)
    {
        x = i;
    }

    public boolean equals(Object rhs)
    {
        if(rhs == null || getClass() != rhs.getClass())
            return false;

        return x == ((BaseClass)rhs).x;
    }
}

class DerivedClass extends BaseClass
{
    private int y;

    public DerivedClass(int i, int j)
    {
        super(i);
        y = j;
    }

    public boolean equals(Object rhs)
    {
        return super.equals(rhs) &&
            y == ((DerivedClass)rhs).y;
    }
}

public class EqualsWithInheritance
{
    public static void main(String[] args)
    {
        BaseClass a = new BaseClass(5);
        DerivedClass b = new DerivedClass(5, 8);
        DerivedClass c = new DerivedClass(5, 8);

        System.out.println("b.equals(c): " + b.equals(c));
        System.out.println("a.equals(b): " + a.equals(b));
        System.out.println("b.equals(a): " + b.equals(a));
    }
}

실행 결과는 다음과 같습니다.
b.equals(c): true
a.equals(b): false
b.equals(a): false
 

요약:


대상의 equals () 방법은 계승 관계를 결합할 때 헷갈리기 쉽다.중요한 것은 우리의 논리적 정의에 따라 부류와 자류의 차이를 상세하게 고려해야 한다면 Object를 고려해야 한다는 것이다.getClass () 는 instanceof가 아닙니다.
 

참고 자료


Inside the java 2 virtual machine
Data structures & problem solving Using java

좋은 웹페이지 즐겨찾기