에 대한 실제 답변
왜이 Comparator
인터페이스하지만 Hasher
과는 Equator
?
Josh Bloch가 인용 한 예입니다 .
원래 Java API는 마감 시한에 맞춰 매우 빠르게 마감되어 시장 마감 시간을 맞이했습니다. 원래 Java 팀은 놀라운 작업을 수행했지만 모든 API가 완벽하지는 않습니다.
문제는 다른 유사한 문제, 예와 마찬가지로, 자바의 역사에서 유일하게 놓여 .clone()
대 Cloneable
.
tl; dr
역사적 이유로 주로; 현재의 행동 / 추억은 JDK 1.0에서 도입되었으며, 이전 버전의 코드 호환성을 유지하는 것이 사실상 불가능했기 때문에 나중에 수정되지 않았습니다.
먼저 몇 가지 잘 알려진 Java 사실을 요약 해 보겠습니다.
- Java는 처음부터 현재까지 이전 버전과의 호환성을 자랑스럽게 생각했으며, 레거시 API는 최신 버전에서 계속 지원되어야합니다.
- 따라서 JDK 1.0에 도입 된 거의 모든 언어 구성 요소는 현재까지 살아 왔으며
Hashtable
, .hashCode()
및 .equals()
JDK 1.0 (구현 된 해시 테이블 )
Comparable
/ Comparator
는 JDK 1.2 ( Comparable ) 에서 소개되었습니다 .
이제 다음과 같습니다.
- 그것은 사실상 불가능 및 개조에 무감각했다
.hashCode()
및 .equals()
여전히 사람들 후 이전 버전과의 호환성을 유지하는 예 있기 때문에 객체 (superobject)에 이르렀보다 더 추상화가가 실현 동안 서로 다른 인터페이스에 각자 1.2으로 자바 프로그래머하는 모든는 것을 알고 Object
그들을 가지고, 그들은했다 컴파일 된 코드 (JVM) 호환성을 제공하기 위해 물리적으로 거기에 머무르고 Object
실제로 구현 한 모든 서브 클래스에 명시 적 인터페이스를 추가하면 이 엉망이 Clonable
하나가 될 것입니다 ( Bloch는 EJ 2nd에서도 논의 된 Cloneable sucks 에 대해 논의합니다) SO를 포함한 다른 많은 장소)
- 그들은 미래 세대가 지속적으로 WTF의 출처를 갖도록 방치했습니다.
이제 " Hashtable
이것과 함께 무엇을 가지고 있습니까?"
대답은 : hashCode()
/ equals()
계약 및 1995과 1996의 핵심 자바 개발자의 그리 좋은 언어 설계 기술.
1996 년 4 월 4 일자 Java 1.0 언어 사양 에서 인용 Object
: The Class , p.41 :
방법 equals
과 (§21.7) hashCode
과 같은 해시 테이블의 이점을 위해 선언되었습니다 java.util.Hashtable
. equals 방법은 객체 평등 개념을 정의하며, 이는 기준이 아닌 값을 기준으로합니다.
(이 정확한 문이되었습니다 유의 변경 , 말, 이후 버전에서 견적 : The method hashCode is very useful, together with the method equals, in hashtables such as java.util.HashMap.
그것은 불가능 직접적인을 할 수있게 Hashtable
- hashCode
- equals
역사적 JLS을 읽지 않고 연결을!)
Java 팀은 좋은 사전 스타일 컬렉션을 원한다고 결정하고 Hashtable
지금까지 좋은 아이디어를 만들었지 만 프로그래머는 가능한 한 적은 코드 / 학습 곡선으로 사용할 수 있기를 원했습니다. 그리고 아직 제네릭이 없었기 때문에 (결국 JDK 1.0), 모든 Object
입력 Hashtable
이 명시 적으로 일부 인터페이스를 구현해야 한다는 것을 의미합니다 (인터페이스는 여전히 초기에 시작 Comparable
되었지만 아직까지는 없었습니다 !). , 이것을 많은 사람들이 사용하기 위해 억제하거나- 해시 방법 Object
을 암시 적으로 구현 해야합니다 .
분명히, 위에서 설명한 이유로 솔루션 2를 사용했습니다. 네, 이제 우리는 그들이 틀렸다는 것을 압니다. ... 후시가 현명 해지기 쉽습니다. 킬킬 웃음
이제 hashCode()
모든 객체는 별개 가지고있다 갖는 필요 equals()
방법 은 그 아주 명백했다, 그래서 - equals()
에 넣어했다 Object
뿐만 아니라.
때문에 기본 유효한에 이러한 방법의 구현 a
및 b
Object
의 중복 됨으로써 본질적으로 쓸모가 (하고 a.equals(b)
동일 에 a==b
와 a.hashCode() == b.hashCode()
거의 동일 로 a==b
, 또한 하지 않는 hashCode
및 / 또는 equals
수십만 오버라이드 (override)되어, 또는 GC Object
응용 프로그램의 수명주기 동안의를 1 ) , 주로 백업 수단으로 사용하기 편리하도록 제공된 것이 안전합니다. 이것은 우리가하는 잘 알려진 사실에 얼마나 정확하게 항상 모두를 오버라이드 (override) .equals()
및 .hashCode()
당신이 실제로 개체를 비교하거나 해시 저장에 대한하려는 경우. 다른 것없이 하나만 재정의하는 것이 코드를 망치는 좋은 방법입니다 (사악한 비교 결과 또는 엄청나게 높은 버킷 충돌 값으로)-머리를 얻는 것은 초보자에게 지속적인 혼란과 오류의 원인입니다 (검색 SO) 더 노련한 사람들에게는 끊임없이 성가신 일입니다.
또한 C #이 equals & hashcode를 조금 더 잘 처리하지만 Eric Lippert 자신도 C #이 시작되기 몇 년 전에 Sun과 Java가했던 것과 거의 같은 실수를했다고 말합니다 .
그러나 왜 모든 객체가 해시 테이블에 삽입하기 위해 스스로 해시 할 수 있어야 하는가? 모든 물체가 할 수 있어야하는 이상한 것 같습니다. 오늘 형식 시스템을 처음부터 새로 디자인했다면 해시가 IHashable
인터페이스 와 다르게 다르게 수행 될 수 있다고 생각합니다 . 그러나 CLR 형식 시스템을 설계 할 때는 일반 형식이 없었으므로 모든 개체를 저장할 수있는 범용 해시 테이블이 필요했습니다.
1 물론 Object#hashCode
수는 여전히에서 충돌하지만 그렇게 노력 약간의 소요, 참조 : http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6809470 자세한 내용 및 링크 된 버그 리포트; https://stackoverflow.com/questions/1381060/hashcode-uniqueness/1381114#1381114 에서이 주제를보다 심도있게 다룹니다.
Person
예상equals
및hashCode
동작 을 구현하는 래퍼 객체를 항상 도입 할 수 있습니다 . 그러면 님이 있습니다HashMap<PersonWrapper, V>
. 이것은 순수 -OOP 접근 방식이 우아하지 않은 한 가지 예입니다. 객체의 모든 작업이 해당 객체의 방법으로 이해되는 것은 아닙니다. 자바의 전체Object
단지는 - 유형은 다른 책임의 아말감이다getClass
,finalize
및toString
방법은 오늘날의 모범 사례를 원격으로 정당한 것처럼 보인다.