2012-12-01 2 views
1

II는 Comparable 인터페이스를 구현할 때 클래스의 자연 순서가 "equals와 일치해야"하는 것을 어떻게 이해할 수 없습니다. 프로그램에서 결함을 발견 했으므로 인터페이스 Comparable의 문서에서 확인했습니다. 내 문제는 두 개체가 equals 메서드의 기본에서 별개로 간주되지만 TreeMap 구조는 해당 개체를 동일한 것으로 간주하므로 결과적으로 두 번째 삽입을 허용하지 않는다는 것입니다. 샘플 코드 :Comparable를 사용하여 TreeMap에서 객체를 비교하고 정렬 비교

public class Car implements Comparable<Car> { 

int weight; 
String name; 

public Car(int w, String n) { 
    weight=w; 
    name=n; 
} 

public boolean equals(Object o){ 
    if(o instanceof Car){ 
     Car d = (Car)o; 
     return ((d.name.equals(name)) && (d.weight==weight)); 
    } 
    return false; 

} 

public int hashCode(){ 
    return weight/2 + 17; 
} 

public String toString(){ 
    return "I am " +name+ " !!!"; 
} 


public int compareTo(Car d){ 
    if(this.weight>d.weight) 
     return 1; 
    else if(this.weight<d.weight) 
     return -1; 
    else 
     return 0; 
} 

/*public int compareTo(Car d){ 
    return this.name.compareTo(d.name); 
}*/ 

} 



public static void main(String[] args) { 
    Car d1 = new Car(100, "a"); 
    Car d2 = new Car(110, "b"); 
    Car d3 = new Car(110, "c"); 
    Car d4 = new Car(100, "a"); 

    Map<Car, Integer> m = new HashMap<Car, Integer>(); 
    m.put(d1, 1); 
    m.put(d2, 2); 
    m.put(d3, 3); 
    m.put(d4, 16); 

    for(Map.Entry<Car, Integer> me : m.entrySet()) 
    System.out.println(me.getKey().toString() + " " +me.getValue()); 

    TreeMap<Car, Integer> tm = new TreeMap<Car, Integer>(m); 
    System.out.println("After Sorting: "); 
    for(Map.Entry<Car, Integer> me : tm.entrySet()) 
     System.out.println(me.getKey().toString() + " " +me.getValue()); 
} 

출력은 :

오브젝트 C가 (어느 정도) 대상 (B)를 대체했다고한다
I am a !!! 16 

I am c !!! 3 

I am b !!! 2 

After Sorting: 

I am a !!! 16 

I am c !!! 2 

. 이 예상 내가 언급 원래 방법과 동일하고, 두 번째는 이름을 따라 개체를 비교하는 방법을 동일의 주석 경우, 출력은 다음과 같습니다

I am a !!! 16 

I am c !!! 3 

I am b !!! 2 

After Sorting: 

I am a !!! 16 

I am b !!! 2 

I am c !!! 3 

는 왜 이런 식으로 돌아올 않고 나는 위해 무엇을 변경해야 TreeMap에 같은 값의 몇개의 속성을 가지는 다른 오브젝트를 삽입 및 소트하기 위해서

답변

2

, compareTo()는 이름을 조사 할 필요가 :

public int compareTo(Car d){ 
    if(this.weight>d.weight) 
     return 1; 
    else if(this.weight<d.weight) 
     return -1; 
    return this.name.compareTo(d.name); 
} 

equals()과 일치 compareTo()을 (후자는 이제 이전의 관점에서 다시 작성할 수 있습니다) 할 것입니다. 또한지도는 이름이 다른 경우 동일한 가중치를 가진 여러 항목을 허용합니다.

1

즉, 개체 c가 (다소) 개체 b를 대체했다는 것입니다.

예, 가능합니다. 그들은 동일한 가중치를 가지므로 TreeMap은 이들이 동일하다고 간주합니다. 지도에는 결코 두 개의 "동등한"키가 포함되지 않습니다 (값을 어떻게 찾을 것입니까?) 따라서 하나는 다른 키를 대체합니다.

평등하다고 생각하지 않으려면 compareTo 방법을 두 번째 정렬 순서로 name을 사용하여 구분해야합니다.

documentation for TreeMapcompareTo 방법 (그렇지 않은하는) 당신의 equals 방법과 일치하지 않은 경우, 당신은 정상 Map 작동하지 것이라고 설명 :

참고하는 트리 맵에 의해 유지되는 주문, 소트 맵과 같이, 명시적인 콤퍼레이터가 제공되고 있는지 어떤지는, 소트 맵이 Map 인터페이스를 올바르게 구현하고있는 경우는, equals와의 일관성이 필요합니다. equals와의 일관성에 대한 정확한 정의는 Comparable 또는 Comparator를 참조하십시오. 이것은, Map 인터페이스가 equals 오퍼레이션의 관점에서 정의되고 있기 (위해) 때문에, sortTo 맵은 compareTo (또는 compare) 메소드를 사용해 모든 키를 비교하기 위해 이 메소드에 의해 등가라고 보여지는 키는 소트 맵의 관점에서 보면 동등합니다. 소트 된 맵의 동작은, 그 순서가 equals와 일치하지 않는 경우에서도, 잘 정의되고 있습니다. 그것은 Map 인터페이스의 일반 계약에 복종하지 않습니다.

+0

Map (HasMap)은 주어진 요소를 다른 이름으로 받아들이므로 TreeMap도 처리해야한다고 생각했습니다. HashMap는 equals 메소드를 고려하여 두 객체를 구별합니다. TreeMap은 요소의 삽입을 허용하거나 거부하지 않기 위해 정렬을 위해서만 compareTo를 사용한다고 생각했습니다. – arjacsoh

+0

@arjacsoh :'TreeMap' 문서를 읽었습니까? 이것에 대해서는 약간 자세히 설명되어 있습니다. –

+0

TreeMap doc로부터 : "그러나 맵은 compareTo (또는 compare) 메소드를 사용하여 모든 키 비교를 수행하므로,이 메소드에 의해 동등한 것으로 간주되는 두 개의 키는 정렬 된 맵의 관점에서 같음". 그래서 그것은 정렬을 위해서가 아니라 "모든 키 비교"를 위해 compareTo를 사용합니다. – arcy

0

compareTo() 방법하지 consistent with equals()이다

경우에만 c.compare(e1, e2)==0 경우 위해 e1.equals(e2) 같은 부울 값을 갖는 모든 e1e2 [...].

대신을 시도해보십시오

public int compareTo(Car d){ 
    if(this.weight>d.weight) 
     return 1; 
    else if(this.weight<d.weight) 
     return -1; 
    else 
     return this.name.compareTo(d.name); 
} 

를 원래의 구현에서 그들은 같은 weight하지만 서로 다른 name이있을 때 그들이 equals()의 측면에서 다른 동안 두 개체가, 비교의 측면에서 동일한 것으로 간주됩니다. 두 가중치가 동일한 경우

0

Comparable interface doc는 "클래스 C의 자연 순서 부는 e1.compareTo (e2) == 0이 e1.equals (e2)와 동일한 부울 값을 갖는 경우에만 equals와 일관성이 있다고합니다. 클래스 C의 모든 e1과 e2 ". 그러나 compareTo()는 이름 필드의 동등성을 검사하지 않기 때문에 그렇게하지 않습니다. compareTo()에 체크를하면 작동한다.