2009-10-15 6 views
3

제목을 쓴 후에도 여전히 Java에서 동등한 버그 교정 구현에 관한 질문을 한 후에이 SO post을 읽었습니다. 이것은 나의 일반적인 구현이다.효율적인 equals (Object o) 구현

@Override 
     public boolean equals(Object o){ 
      if(o == null) return false; 
      if(o instanceof CompositePk == false) return false; 
      if(this == o) return true; 
      CompositePk that = (CompositePk)o; 
      return new EqualsBuilder().append(this.id, that.id) 
             .append(this.bucketId, that.bucketId) 
             .isEquals(); 
     } 

평범한 것을하기 위해 Apache의 EqualsBuilder를 사용한다. 이 내하고, NetBean의 자동 생성 equals(o) 구현

@Override 
     public boolean equals(Object obj){ 
     if (obj == null) { 
       return false; 
      } 
      if (getClass() != obj.getClass()) { 
       return false; 
      } 
      final TemplatesWrapper other = (TemplatesWrapper) obj; 
      if (this.timeAdded != other.timeAdded && (this.timeAdded == null || !this.timeAdded.equals(other.timeAdded))) { 
       return false; 
      } 
      return true; 
    } 

보다 더 쉬운 나는 2 개 DIFF 프로젝트에서 다음을하지만 그들은 모두 같은 일을하지만 사랑하는 방법을 사용하여 작업을 수행하려고합니다. 어느 스타일을 사용 하시겠습니까? 아니면 어떤 결함이 있습니까? 중간에

public boolean equals(Object ob) { 
    if (ob == null) return false; 
    if (ob == this) return true; 

    if (!(ob instanceof MyClass)) return false; // OR 
    if (ob.getClass() != getClass()) return false; 

    // check relevant members 
} 

두 개의 선이 다른 :

답변

5

나는 이런 식으로 할 것이다. 하나는 서브 클래스가 같도록 허용하고 (첫 번째 서브 클래스는), 다른 서브 클래스는 동일하지 않습니다. 어느 것이 든 적합한 것을 사용하십시오.

정확한 구현 인 List은 관련이 없기 때문에 Java의 AbstractList 클래스는 두 번째 형식을 사용합니다. 중요한 것은 회원들이 평등하고 동일한 지위에있는 경우입니다.

반대로, Student 하위 클래스가 있고 Person.equals(Student)을 호출하면 Person 클래스는 Person의 추가 필드를 확인하지 않고 true를 반환하는 반면 Student.equals (Person)는 아마도 false을 반환하기 때문에 첫 번째 양식 (instanceof)을 사용해야합니다. . equals()이 교환 적이 지 않으면 문제가 생길 것입니다.

약간의 아파치 라이브러리에 불필요한 의존성을주지 않고 내 IDE (IntelliJ IDEA)에서 생성 한 메서드를 사용하는 경향이 있습니다.

+1

저는 이러한 이유로 Apache Commons EqualsBuilder를 사용하는 것이 좋습니다. 새 필드를 추가 할 때 사용하는 유지 관리가 적습니다. 그러나 필드를 추가 할 때마다 IDEA가 '평등'을 재생성하기 만하면된다고 주장 할 수도 있습니다. 각각 자신에게. :-P –

+0

당신은'||'연산자에 대해 알고 있습니까? ;-) –

0

아파치가 너의 것보다 낫다.

나의 모호한 기억이 암시하는 한, instanceof을 equals에 사용하는 데 문제가 있습니다. 나는 왜 아직 내 손가락을 넣을 수는 없지만 누군가가 정교하게 만들 것입니다. 내가 틀렸을 수도있다.

- 편집 :

Chris으로하고 Steve이 유용하게 나는 "symmetric property"생각하고 있었는데, 아래의 설명은 구현 같습니다. 이를 바탕으로, 나는 아파치 구현 : 모든

+3

'instanceof'를 사용할 때의 문제는 객체 하나의 클래스 A와 클래스 B의 객체를 비교할 때 비대칭입니다. 여기서 B는 하위 클래스 A입니다.하지만 "클래스 평등"비교는 훨씬 더 나쁩니다. 대체 가능성에 따라 동일해야한다고하더라도 하위 클래스는 수퍼 클래스 인스턴스와 같은 것으로 간주되지 않습니다. 즉, 'instanceof'는 두 가지 악의 중 적은 것입니다. –

+1

instanceof를 사용하면 'symmetric 속성이 같음을 위반합니다. 즉, y.equals (y)가 true 인 경우에만 x.equals (y)가 true가됩니다. 이것은 getClass를 사용하는 클래스가 기술적으로 올바른 클래스를 비교하는 것입니다. –

+0

스티브 : 예, 그게 전부입니다. 감사. 내가 이것을 가져 왔음에도 불구하고 downvoted되었지만, 당신이 설명 했으므로 모든 것이 잘되어있다. :) –

9

먼저 선호한다 나의 주장을 백업 할 수 있습니다, 다음, null 테스트 foonullfoo instanceof Barfalse로 평가하기 때문에, instanceof를 테스트 할 필요가 없습니다.

instanceof 연산자의 결과를 false과 비교하는 것은 이상한 일입니다. instanceof은 부울 연산입니다.

클래스를 getClass()과 비교하는 것은 논쟁의 여지가 많습니다.자바 컬렉션 프레임 워크와 이외의 다른 중요한 물건을 많이 많이 쓴 조슈아 블로흐, says

이 기술은 ("getClass 기반이 방법과 동일") 등호를 계약을 만족하지 않습니다,하지만 큰 비용 . getClass 접근 의 단점이 서브 클래스 인스턴스되게 때 슈퍼 클래스 인스턴스를 기대하는 방법 가 제대로 작동해야합니다 (대략 말하기) 를 내용의 "Liskov 대체의 원리를"위반하는 것입니다. 서브 클래스가 몇 가지 새로운 방법, 또는 사소 (예를 들어, 각 메소드 호출시 추적을 방출에 의해) 동작을 수정을 추가하는 경우 서브 클래스와 슈퍼 클래스 인스턴스가 제대로 상호 작용하지 않는 때, 프로그래머 놀라게 될 것입니다. 이 "같아야 함"인 개체는 그렇지 않으므로 프로그램이 실패하거나 이 비정상적으로 작동합니다. 문제는 은 Java의 콜렉션이 메소드를 기반으로한다는 사실에 의해 악화됩니다.

특정 기술적 인 이유가없는 한 getClass()을 통해 비교하는 대신 instanceof을 사용해야합니다.

다른 개체가 this과 비슷하다는 것을 확인한 후에 == 및 개체를 equals으로 비교합니다. 멤버 객체 중 하나라도 null 일 수 있으면 더 복잡합니다. null 항목을 서로 비교하기 위해 verbose 절을 ​​작성해야합니다 (또는 bothNullOrEqual(Object a, Object b) 메소드 작성).

EqualsBuilder 접근 방식은 나에게 가짜로 보일 뿐이지 만 그건 기술적으로 반대하지 않을 "냄새"입니다. 일반적으로 자주 호출 될 수있는 메서드에서 추가 메서드 호출을 좋아하지 않습니다.

null을 테스트하고 getClass() 비교를 사용하기 때문에 Apache 하나가 가짜입니다.

다음은 내 꺼야 :

@Override 
public boolean equals(final Object o) { 
    if (!(o instanceof MyClass)) 
     return false; 
    final MyClass om = (MyClass)o; 
    // compare om's fields to mine 
} 
+0

'EqualsBuilder'는 최소한 두 버전이 비교되지 않는 한'getClass' 비교를하지 않습니다. 이것은 실제로 공정한 게임입니다 (대부분의 경우). –

+1

최종본은 무엇입니까? 옴을 재 할당 할까 봐 걱정 되니? –

+2

'최종'은 추론에 도움이됩니다. 더 많은 것을 읽으면서 생각할 사항은 하나도 적습니다. Java에서 모든 것이 '변경 가능'으로 표시되지 않는 한 '최종'이라고합니다. –

0

솔직히, 당신이 작성해야 덜 코드, 오프 더 나은 있습니다 (대부분의 경우).

생성 된 코드는 많은 사람들이 디버깅하고 사용했습니다. 생성 된 내용을 사용할 수도 있습니다 (성능 향상이 필요한 경우 그렇게하십시오).

생성 된 코드를 사용할 때의 이점 : 인스턴스 필드가 변경 될 때마다 (그리고 생성 된 코드가 수정되지 않았을 때) 간단하게 코드를 다시 생성 할 수 있습니다.

때로는 유지 관리 가능성에 대해 생각하는 것이 더 쉽습니다. 엄지의 법칙 : 스스로 작성하는 코드가 적을수록 디버그 할 필요가 줄어 듭니다. 생성 된 코드가 큰 성능을 발휘하지 않으면 생성하십시오!

0

설명 : equals 메서드를 재정의하는 경우 hashCode() 메서드도 재정의해야합니다. 따라서 아래에 표시된 3 가지 속성을 가진 클래스를 고려하고 모든 속성이 동등성에 중요하다는 점을 고려하면 equals() 구현은 이러한 모든 필드를 테스트해야합니다.조건부의 순서는 중요하지 않지만 모든 필드는 객체 간의 평등을 고려해야하는 평등성에 대해 테스트해야합니다.

public class SampleClass { 

    private Long id; 
    private String description; 
    private Date creation; 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + ((creation == null) ? 0 : creation.hashCode()); 
     result = prime * result + ((description == null) ? 0 : description.hashCode()); 
     result = prime * result + ((id == null) ? 0 : id.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     boolean isEquals = true; 
     if (this == obj) { isEquals = true; } 
     else if (obj == null) { isEquals = false; } 
     else if (getClass() != obj.getClass()) { isEquals = false; } 
     else { 
      SampleClass other = (SampleClass) obj; 
      if (creation == null) { 
       if (other.creation != null) isEquals = false; 
      } else if (!creation.equals(other.creation)) { 
       isEquals = false; 
      } else if (description == null) { 
       if (other.description != null) isEquals = false; 
      } else if (!description.equals(other.description)) { 
       isEquals = false; 
      } else if (id == null) { 
       if (other.id != null) isEquals = false; 
      } else if (!id.equals(other.id)) { 
       isEquals = false; 
      } 
     } 
     return isEquals; 
    } 
+0

답변에 몇 가지 설명을 추가하는 것이 좋습니다. – fedorqui

관련 문제