equal 에 대한 깊이 있 는 연구

equal 에 대한 깊이 있 는 연구
equals 방법의 중요성 은 더 말 할 필요 가 없다. 네가 비교 하고 싶 은 두 대상 이 같은 대상 이 되 기 를 원 하지 않 는 다 면 너 는 반드시 실현 해 야 한다.
equals 방법, 대상 을 동일 하 다 고 생각 하 는 조건 으로 비교 하도록 합 니 다.
 
아래 의 내용 은 API 의 규범 일 뿐 그다지 깊 은 의 미 는 없 지만 제 가 가장 먼저 그것 을 여기에 열거 한 이 유 는...
이런 규범 들 은 사실 에서 결코 진정 으로 실현 을 보장 할 수 있 는 것 이 아니다.
 
1. 모든 인용 유형 에 대해 o. equals (o) = = true 가 성립 됩 니 다.
2. 만약 o. equals (o1) = = true 가 성립 된다 면 o1. equals (o) = = true 도 반드시 성립 되 어야 한다.
3. o. equals (o1) = = true 가 성립 되 고 o. equals (o2) = = true 가 성립 된다 면
o1. equals (o2) = = true 도 성립 됩 니 다.
4. 첫 번 째 호출 o. equals (o1) = = true 성립 재 o 와 o1 이 변 하지 않 은 경우 이후 의 어떠한 호출 도
모두 성립 되다.
5. o. equals (null) = = true 는 어떠한 시간 도 성립 되 지 않 습 니 다.
 
상기 몇 가지 규칙 은 가장 완전한 표현 이 아 닙 니 다. 상세 한 것 은 API 문 서 를 참조 하 십시오.
 
Object 류 에 있어 서 가장 엄밀 한 실현 을 제공 합 니 다. 그것 은 바로 같은 대상 만 이 'equals 방법' 이 true 로 돌아 가 는 것 입 니 다. 즉, 사람들 이 흔히 말 하 는 인용 비교 이지 값 비교 가 아 닙 니 다. 이 실현 은 실제 적 인 의미 가 없 을 정도 로 엄밀 하기 때문에 구체 적 인 하위 클래스 (Object 에 비해) 에서 우리 가 대상 의 값 을 비교 하려 면자신의 equals 방법 을 실현 해 야 합 니 다.
 
먼저 다음 절 차 를 살 펴 보 겠 습 니 다.
    public boolean equals(Object obj)    {        if (obj == null) return false;        if (!(obj instanceof FieldPosition))            return false;        FieldPosition other = (FieldPosition) obj;        if (attribute == null) {            if (other.attribute != null) {                return false;            }        }        else if (!attribute.equals(other.attribute)) {            return false;        }        return (beginIndex == other.beginIndex            && endIndex == other.endIndex            && field == other.field);    }
 
이것 은 JDK 에서 자바. text. FieldPosition 의 표준 실현 으로 할 말 이 없 는 것 같 습 니 다.
 
나 는 대부분의 프로그래머 나 절대 다수의 프로그래머 들 이 이것 이 정확 하고 합 법 적 인 equals 실현 이 라 고 생각한다. 왜냐하면 이것 은 JDK 의 API 실현 이기 때문이다.
 
사실 로 말 합 시다.
package debug;import java.text.*;public class Test {  public static void main(String[] args) {    FieldPosition fp = new FieldPosition(10);    FieldPosition fp1 = new MyTest(10);    System.out.println(fp.equals(fp1));    System.out.println(fp1.equals(fp));  }}class MyTest extends FieldPosition{  int x = 10;  public MyTest(int x){    super(x);    this.x = x;  }  public boolean equals(Object o){    if(o==null) return false;    if(!(o instanceof MyTest )) return false;    return ((MyTest)o).x == this.x;  }}
무엇이 인쇄 되 는 지 실행 해 보 세 요.
 
System.out.println(fp.equals(fp1));인쇄 true
System.out.println(fp1.equals(fp));인쇄 flase
 
두 대상 에 게 비대 칭 equals 알고리즘 이 나 타 났 습 니 다. 문 제 는 어디 에 있 습 니까?
 
나 는 많은 프로그래머 들 이 equals 방법 을 전혀 모 르 는 프로그래머 들 을 제외 하고 equals 방법 을 실현 하고 있다 고 믿는다.
인 스타 그램 운영 자 를 사용 하여 단락 최 적 화 를 한 적 이 있 습 니 다. 실사구시 적 으로 오랫동안 저도 이렇게 사용 한 적 이 있 습 니 다.
너무 많은 튜 토리 얼 이 우리 에 게 이런 오 도 를 주 었 다.약간 아 는 프로그래머 들 은 이런 최적화 가능성 을 알 수 있다.
좀 틀 렸 지만 문제 의 관건 을 찾 지 못 했다.또 다른 극단 은 이 기술적 결함 을 아 는 유골 급 전문가 가 이 를 원 하지 않 는 다 고 제안 한 것 이다.
견본 응용.
 
우 리 는 '보통' 이 두 대상 을 비교 해 야 한 다 는 것 을 알 고 있다. 그러면 그들 은 '마 땅 히' 가 같은 유형 이 어야 한다.그래서 우선 인 스 턴 스 of 를 이용 해 요.
실행 부 호 를 단락 최적화 합 니 다. 비교 대상 이 현재 대상 과 같은 유형 이 아니라면 false 로 돌아 가지 않 아 도 됩 니 다. 그러나 사실 입 니 다.
"하위 클래스 는 부모 클래스 의 인 스 턴 스 입 니 다". 따라서 하위 클래스 o instanceof 부모 클래스 가 처음부터 끝까지 true 로 돌아 가면 분명 합 니 다.
단락 최적화 가 발생 하지 않 고 아래 의 비 교 는 여러 가지 상황 이 발생 할 수 있다. 하 나 는 부 류 를 조형 하지 못 하고 이상 을 던 지 는 것 이 고 다른 하 나 는
아버지 류 의 private 멤버 는 이불 류 의 계승 이 없어 비교 할 수 없 으 며, 위의 비대 칭 비 교 를 형성 하 는 것 이다.이 가능 하 다, ~ 할 수 있다,...
너무 많은 상황 이 발생 할 것 이다.
 
 
그렇다면 인 스타 그램 운영 자 를 최적화 할 수 없 는 것 일 까?정 답 은 부정 적 이 고, JDK 에 서 는 여전히 많은 실현 이 긍정 적 이다.
확실한 것 은 만약 에 하나의 class 가 final 이 라면 하위 클래스 가 있 을 수 없다 는 것 을 알 면서 왜 instanceof 로 최적화 하지 않 습 니까?
 
썬 의 개발 팀 의 명 예 를 지 키 기 위해 서 나 는 어떤 유형 중 하 나 를 설명 하지 않 지만, 한 팀 의 구성원 이 이 방법 으로 최적화 할 때 나중에 추가 합 니 다.
이런 주석 을 달 았 습 니 다.
        if (this == obj)                      // quick check            return true;        if (!(obj instanceof XXXXClass))         // (1) same object?            return false;
의문 이 있 었 는 지 어떻게 해 야 할 지 모 르 겠 어 요.
 
그렇다면 비 final 류 에 대해 서 는 어떻게 유형의 quick check 을 진행 합 니까?
 
if(obj.getClass() != XXXClass.class) return false;
 
비교 대상 의 클 라 스 대상 과 현재 대상 의 클 라 스 를 비교 하 는 것 은 문제 가 없 는 것 처럼 보이 지만, 이 클래스 의 하위 클래스 가
equals 방법 을 다시 실현 하지 않 았 다 면 하위 클래스 를 비교 할 때 obj. getClass () 는 XXXCalss. class 와 같 지 않 을 것 입 니 다.
즉, 하위 클래스 의 equals 가 올 바 르 지 않 기 때문에 if (obj. getClass ()! = this. getClass () return false;바로
확실한 비교.
 
 
equals 방법 이 반드시 비교 해 야 하 는 두 대상 은 반드시 같은 유형 이 어야 합 니까?위 에서 나 는 '보통' 을 사 용 했 는데, 이것 도 절대 다수의 프로그램 이다.
직원 의 소망 이지 만 어떤 특수 한 상황 에서 우 리 는 서로 다른 유형의 비 교 를 할 수 있 는데 이것 은 규범 에 어 긋 나 지 않 는 다.그러나 이런 특수 한 상황 은
매우 보기 드 문 것 입 니 다. 하나의 부적 절 한 예 는 Integer 류 의 equals 가 Sort 와 비교 할 수 있 고 그들의 value 를 비교 할 수 있 습 니 다.
같은 수학 값 입 니 다.(사실 JDK API 에 서 는 그렇게 하지 않 았 기 때문에 부적 절 한 예 라 고 말 하 는 것)
 
quick check 을 완성 한 후에 우 리 는 당신 이 생각 하 는 '같다' 는 것 을 진정 으로 실현 해 야 합 니 다.실현 대상 이 같다 면 그다지 높 지 않다.
의 요구, 예 를 들 어 당신 이 실현 한 '사람' 류 는 name 이 같 으 면 그들 이 같다 고 생각 하고 다른 sex 라 고 생각 할 수 있 습 니 다.
생각 안 해도 돼.이것 은 완전히 실현 되 지 는 않 지만 완전히 실현 된다 면 모든 속성 이 똑 같 아야 한다.
어떻게 equals 방법 을 실현 합 니까?
 class Human{private String name;private int ago;private String sex;        ....................        public boolean equals(Object obj){quick check.......Human other = (Human)ojb;return this.name.equals(other.name)&& this.ago == ohter.ago&& this.sex.equals(other.sex);}}
이것 은 완전히 실현 되 는 것 이지 만, 때로는 equals 실현 은 아버지 류 에서 이 루어 지 는 것 이 고, 이불 류 의 계승 후 equals 가 정확 한 작업 을 할 수 있 도록 요구한다.
이 럴 때 하위 클래스 가 어떤 속성 을 확장 하 는 지 알 지 못 하기 때문에 위의 방법 으로 equals 를 완전히 실현 할 수 없습니다.
좋 은 방법 은 반 사 를 이용 하여 equals 를 완전히 실현 하 는 것 이다.
        public boolean equals(Object obj){quick check.......Class c = this.getClass();Filed[] fds = c.getDeclaredFields();for(Filed f:fds){if(!f.get(this).equals(f.get(obj)))return false;}return true;}
설명 의 편 의 를 위해 상명 의 실현 은 이상 을 생략 하 였 습 니 다. 이러한 실현 은 아버지 류 에 두 면 당신 의 하위 클래스 의 equals 가 누 를 수 있 도록 보장 할 수 있 습 니 다.
너의 소망 은 정확하게 일한다.
 
equals 방법 에 대한 마지막 점 은 equals 방법 을 다시 쓰 면 equals 방법 과 동시에
반드시 hashCode () 를 다시 써 야 합 니 다. 규범 이 어야 합 니 다. 그렇지 않 으 면...........................................
우 리 는 이 예 를 살 펴 보 자.
public final class PhoneNumber {    private final int areaCode;    private final int exchange;    private final int extension;    public PhoneNumber(int areaCode, int exchange, int extension) {        rangeCheck(areaCode, 999, "area code");        rangeCheck(exchange, 99999999, "exchange");        rangeCheck(extension, 9999, "extension");        this.areaCode = areaCode;        this.exchange = exchange;        this.extension = extension;    }    private static void rangeCheck(int arg, int max, String name) {        if(arg < 0 || arg > max)            throw new IllegalArgumentException(name + ": " + arg);    }    public boolean equals(Object o) {        if(o == this)            return true;        if(!(o instanceof PhoneNumber))            return false;        PhoneNumber pn = (PhoneNumber)o;        return pn.extension == extension && pn.exchange == exchange && pn.areaCode == areaCode;    }}
 
이 종 류 는 final 이기 때문에 이 equals 실현 에는 문제 가 없습니다.
 
테스트 해 보 겠 습 니 다.
    public static void main(String[] args) {        Map hm = new HashMap();        PhoneNumber pn = new PhoneNumber(123, 38942, 230);        hm.put(pn, "I love you");        PhoneNumber pn1 = new PhoneNumber(123, 38942, 230);        System.out.println(pn);        System.out.println("pn.equals(pn1) is " + pn.equals(pn1));        System.out.println(hm.get(pn1));        System.out.println(hm.get(pn));    }
pn. equals (pn1) 라면 넣 겠 습 니 다 (pn, "I love you").후, get (pn1) 이것 은 무엇이 null 입 니까?
정 답 은 hashCode 가 다 르 기 때문에 hashMap 은 hashCode 를 메 인 키 로 합 니 다.
 
따라서 규범 적 인 요 구 는 두 대상 이 equals 를 비교 할 때 true 로 돌아 가면 hashcode 는 같은 값 으로 돌아 가 야 합 니 다.
 
원본 주소:
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=17726&tstart=0

좋은 웹페이지 즐겨찾기