Java에서 동일하게 재정의 할 때 왜 객체 이외의 매개 변수를 사용하는 것이 작동하지 않습니까?

StackOverflow https://stackoverflow.com/questions/309892

  •  08-07-2019
  •  | 
  •  

문제

나는 최근에 흥미로운 행동을 취했다. 객체 이외의 다른 매개 변수를 가져 오도록 .equals ()를 재정의하면 호출되지 않는 것 같습니다. 누구든지 왜 이런 일이 일어나고 있는지 설명 할 수 있습니까? OOP의 다형성에 대한 이해를 침해하는 것 같습니다.

다음은 내가보고있는 것을 보여주는 훨씬 간단한 코드입니다.

public class MyClass {
  private int x;
  public MyClass(int n) { x = n; }
  public boolean equals(Object o) { return false; }
  public boolean equals(MyClass mc) { return x == mc.x; }
  public static void main(String[] args) {
    List<MyClass> list = new ArrayList<MyClass>();
    list.add(new MyClass(3));
    System.out.println("Contains 3? " + list.contains(new MyClass(3)));
  }
}

이것이 실행되면 인쇄 "Contains 3? false". 이는 작동하는 또 다른 것이 있지만 평등 (객체) 함수가 호출되는 것처럼 보입니다. 대조적으로, 이와 같이 똑같이 작성하면 코드는 예상대로 작동합니다.

public boolean equals(Object o) {
  if(!(o instanceof MyClass))
    return false;
  MyClass mc = (MyClass)o;
  return x == mc.x;
}

매개 변수 유형에 따라 어떤 버전의 호출을 호출할지 알아 내지 않는 이유는 무엇입니까?

도움이 되었습니까?

해결책

"재정의"와 "과부하"를 혼합하고 있습니다.

재정의 - 다형성 목적을위한 기존 방법의 대체 정의 추가. 이 메소드는 동일한 서명이 있어야합니다. 서명은 이름과 인수 유형으로 구성됩니다. 대상 객체의 런타임 유형에 따라 런타임에서 재정의 메소드가 선택됩니다.

오버로드 - 이름이 같지만 서명이 다른 메소드를 추가합니다. 과부하 된 방법은 대상 객체의 컴파일 시간 유형에 따라 컴파일 시간에 선택됩니다.

다른 팁

Equals (Object)는 슈퍼 방법을 재정의하고 있습니다. 당신은 할 수 있습니다 ~ 아니다 정확히 동일한 서명을 사용하지 않고 슈퍼 메소드를 대체하십시오 (음, 공분산 반환 유형 및 예외와 같은 예외가 있습니다).

호출중인 메소드는 arraylist를 위해 Javadoc에 정의됩니다.<E> AS

boolean contains(Object o)
    Returns true if this list contains the specified element. 

대신에

boolean contains(E o)
    Returns true if this list contains the specified element. 

ArrayList.java 구현 :

private transient Object elementData[];

public boolean contains(Object elem) {
    return indexOf(elem) >= 0;
}

public int indexOf(Object elem) {
    if (elem == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (elem.equals(elementData[i]))
                return i;
    }
    return -1;
}

arraylist에서 equals 메소드가 재정의되지 않으므로 객체 슈퍼 클래스에 정의 된 Equals 메소드를 사용합니다.<E>의 구현.

객체를 재정의하는 것이 Java에서 동일하면 객체 해시 코드 메소드도 무시해야합니다.

어쨌든 다음 코드를 시도하고 싶을 수도 있습니다.

class A{    
    public int content;    
    A(){
        this(0);
    }    
    A(int value){
        content = value;
    }   
    public boolean equals(Object obj){
        System.out.println("overriding equals method");
        return this.content == ((A) obj).content;
    }    
    public boolean equals(A a){
        System.out.println("overloading equals method");
        return this.content == a.content;
    }    
    public static void main(String[] args){
        A x = new A(1);
        A y = new A(2);
        Object z  = new A(1);
        System.out.println(x.equals(y));
        System.out.println(x.equals(x));
        System.out.println(x.equals(z));
        //override as z is declared as Object at compile time
        //so it will use methods in class Object instead of class A
        System.out.println(x.equals((Object) y));
        System.out.println(x.equals((Object) x));        
    }   
}
//rant: they didn't teach me these in javaschool and I had to learn it the hard way.

포함 (개체) 메소드의 ArrayList 구현은 내부적으로 Object.equals (Object) 메소드를 사용해야하므로 Equals (MyClass) 메소드의 과부하에 대해서는 알 수 없습니다. 우선적 인 메소드 (일치하는 서명) 만 발견됩니다.

알았어.

(1) 컴파일러가 제네릭에 관한 모든 정보를 제거하기 때문에 (삭제, 여기), 및 (2) 정확히 동일한 서명없이 메소드를 무시할 수 없기 때문에 (Equals (Object)), (3) 런타임 동안 목록 내의 모든 객체는 MyClass의 인스턴스가 아닌 개체로 취급됩니다. 따라서 호출되는 방법은 동일 (객체)입니다. 왜냐하면 이것은 수업에 의해 덮어 쓴 것이기 때문입니다.

당신은 그것을 가정하고 있습니다 contains() 방법 List 런타임시 객체의 유형을 알고 있습니다.

삭제 때문에 List<MyClass> 단지 규칙이됩니다 List 런타임에 contains() 메소드는 매개 변수를 an으로 본다 Object, 따라서 객체를 호출합니다 equals() 당신이 정의한 것 대신 MyClass 실행 중.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top