최선의 구현을 위한 방법의 차이에 대한 컬렉션
문제
우리는 어떻게 결정에서의 최적 구현 hashCode()
방법은 컬렉션이(가정과 같은 방법이 다시 정의되었습니다.올바르게)?
해결책
최 구현?그건 어려운 질문이기 때문에 그것을 사용 패턴에 따라.
또한 거의 모든 경우 합리적으로 구현되었고 조쉬 블로흐ko 효과적인 자바 에 항목이 8(second edition).가장 좋은 것은 그것을 찾기 때문에 저자명이 왜 이 방법이 좋다.
짧은 버전
성
int result
및 할당 non-zero 값이 있습니다.대 모든 분야
f
에서 테스트equals()
방법,해시를 계산 코드c
의:- 면 필 f
boolean
:계산(f ? 0 : 1)
; - 면 필 f
byte
,char
,short
나int
:계산(int)f
; - 면 필 f
long
:계산(int)(f ^ (f >>> 32))
; - 면 필 f
float
:계산Float.floatToIntBits(f)
; - 면 필 f
double
:계산Double.doubleToLongBits(f)
고 핸들을 반환 값은 다음과 같 모든 장치 - 면 필 f 체:를 사용하여 결과
hashCode()
방법는 경우에는 0f == null
; - 면 필 f 배열:모든 분야로 별도의 요소 계산 및 해쉬값을 재귀 패션 와 결합하는 값으로 다음에 설명하.
- 면 필 f
을 결합한 해쉬값
c
가result
:result = 37 * result + c
Return
result
이 결과는 적절한 분포 해시의 대부분의 값을 사용하여 상황입니다.
다른 팁
당신은 행복과 Java 효과적인 구현에 의해 추천 dmeister 사용할 수 있습니다,라이브러리 호출신의 회전이 자신의:
@Override
public int hashCode() {
return Objects.hashCode(this.firstName, this.lastName);
}
이 필요로 하는 구아바(com.google.common.base.Objects.hashCode
다)또는 표준 라이브러리에서 Java7(java.util.Objects.hash
다)하지만 같은 방식으로 작동합니다.
그것은 더 나은 사용하는 기능을 제공하여 Eclipse 는 매우 좋은 일을 넣을 수 있습니다 당신의 노력과 에너지 개발에서 비즈니스 논리입니다.
하지만 이것이 연결 Android
문서(Wayback Machine) 고 내 자신의 코드에 Github, 작동을 위한 Java 에서 일반적입니다.나의 응답의 확장 dmeister 의 응답 다만 코드는 많은 쉽게 읽고 이해할 수 있습니다.
@Override
public int hashCode() {
// Start with a non-zero constant. Prime is preferred
int result = 17;
// Include a hash for each field.
// Primatives
result = 31 * result + (booleanField ? 1 : 0); // 1 bit » 32-bit
result = 31 * result + byteField; // 8 bits » 32-bit
result = 31 * result + charField; // 16 bits » 32-bit
result = 31 * result + shortField; // 16 bits » 32-bit
result = 31 * result + intField; // 32 bits » 32-bit
result = 31 * result + (int)(longField ^ (longField >>> 32)); // 64 bits » 32-bit
result = 31 * result + Float.floatToIntBits(floatField); // 32 bits » 32-bit
long doubleFieldBits = Double.doubleToLongBits(doubleField); // 64 bits (double) » 64-bit (long) » 32-bit (int)
result = 31 * result + (int)(doubleFieldBits ^ (doubleFieldBits >>> 32));
// Objects
result = 31 * result + Arrays.hashCode(arrayField); // var bits » 32-bit
result = 31 * result + referenceField.hashCode(); // var bits » 32-bit (non-nullable)
result = 31 * result + // var bits » 32-bit (nullable)
(nullableReferenceField == null
? 0
: nullableReferenceField.hashCode());
return result;
}
편집
일반적으로 무시할 때 hashcode(...)
, 에,당신은 또한 재정의 equals(...)
.그래서 그는 것이거나 이미 구현 equals
, 여기에 좋은 참조 에서 내 Github...
@Override
public boolean equals(Object o) {
// Optimization (not required).
if (this == o) {
return true;
}
// Return false if the other object has the wrong type, interface, or is null.
if (!(o instanceof MyType)) {
return false;
}
MyType lhs = (MyType) o; // lhs means "left hand side"
// Primitive fields
return booleanField == lhs.booleanField
&& byteField == lhs.byteField
&& charField == lhs.charField
&& shortField == lhs.shortField
&& intField == lhs.intField
&& longField == lhs.longField
&& floatField == lhs.floatField
&& doubleField == lhs.doubleField
// Arrays
&& Arrays.equals(arrayField, lhs.arrayField)
// Objects
&& referenceField.equals(lhs.referenceField)
&& (nullableReferenceField == null
? lhs.nullableReferenceField == null
: nullableReferenceField.equals(lhs.nullableReferenceField));
}
첫째는지 확인 같은 구현했습니다.서 IBM DeveloperWorks 문서:
- 대칭:두에 대한 참조,b,a.equals(b)는 경우에만 b.equals(a)
- 상식적인:에 대한 모든 비 null 참조한다.equals(a)
- 전이성:는 경우.equals(b)b.equals(c)음.equals(c)
다음 사항을 확인하십시오들의 관계가 차이를 존중하며 연락처(에서 동일한 문서):
- 일관성과의 차이():두 개의 동일한 개체에 동일해야 합 차()값이
마지막으로 좋은 해쉬 기능을 위해 노력하는 접근 상 hash function.
about8.blogspot.com 말
는 경우 equals()true 를 반환하는 두 개체에 대해 다음의 차()한다 같은 값을 반환합니다.는 경우 equals()가 false 를 반환한 다음의 차()반환해야 합니다 다른 가치
나도 동의할 수 없습니다.는 경우 두 물체가 동일한 차이가 없을 의미하는 것은 그들이 동일하다.
는 경우 같 B 그 A. 해시 코드와 동일해야 B.hascode
지
는 경우 A. 차 equals B.hascode 는 것을 의미하지 않는 합 같 B
당신이 사용하는 경우 이클립스를 생성할 수 있습니다 equals()
고 hashCode()
를 사용:
원본->성의 차이()및 equals().
이 기능을 사용하여 결정할 수 있습니다 어떤 분야 당신이 사용하고 싶은 평등과 해시 코드 계산 및 Eclipse 를 생성하는 해당 방법이 있습니다.
가의 구현 효과적인 자바ko hashcode()
고 equals()
로직 Apache Commons Lang.체크아웃 HashCodeBuilder 고 EqualsBuilder.
그냥 빠른 메모를 완료에 대한 더 자세한 답변(의 기간에 코드):
면을 고려 질문 -어떻게 나 만들기-해시 테이블에서 java 특히 jGuru FAQ 항목, 에,나는 믿고 일부는 다른 기준에는 해시 코드는 판단을 받은:
- 동기화(않 algo 동시 지원에 액세스하거나지 않는)?
- 가 안전하게 반복(않 algo 검색 컬렉션을 변경하는 동안 반복)
- null 값(는 해시드 지원 null 값에서 컬렉션)
는 경우로,당신은 사용자 정의 컬렉션 클래스(예:새로운 클래스를 확장하는 컬렉션에서 인터페이스)을 구현하고자 해시()메소드가 있습니다.
는 경우에 당신의 컬렉션 클래스를 확장 AbstractList,당신은 걱정할 필요가 없이 그것에 대해 이미의 구현 equals()과의 차이()는 작품을 반복하여 모든 개체들 hashCodes()함께.
public int hashCode() {
int hashCode = 1;
Iterator i = iterator();
while (i.hasNext()) {
Object obj = i.next();
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
return hashCode;
}
면 지금 당신이 원하는 것은 최고의를 계산하는 방법에 대한 해시 코드는 특정 클래스 일반적으로 사용하^(비트는 독점 또는)운영자 프로세스는 모든 분야 내가 사용하는에서 같음 방법:
public int hashCode(){
return intMember ^ (stringField != null ? stringField.hashCode() : 0);
}
@about8:가 꽤 심각한 버그가 있다.
Zam obj1 = new Zam("foo", "bar", "baz");
Zam obj2 = new Zam("fo", "obar", "baz");
같은 해시
무언가를 하고자 할 수도 있습니아
public int hashCode() {
return (getFoo().hashCode() + getBar().hashCode()).toString().hashCode();
(당신이 얻을 수 있습니 차에서 직접 int 자바에서 이러한 일입니까?나도 그렇게 생각은 일부가 자동..이 경우에는 건너뛰 toString,그것이다.)
으로 특별히 요청한 컬렉션,추적 측면이 다른 답변을 언급하지 않은 아직:A HashMap 예상하지 못한들 키를 변경해 해시 한 번 그들은 컬렉션에 추가됩니다.전체 목적에 적...
를 사용하여 반사 방법 Apache Commons EqualsBuilder 고 HashCodeBuilder.
어떤 해싱하는 방법을 균등하게 분산 해쉬값을 통해 가능한 범위로 구현.보 효과적인 자바( http://books.google.com.au/books?id=ZZOiqZQIbRMC&dq=effective+java&pg=PP1&ots=UZMZ2siN25&sig=kR0n73DHJOn-D77qGj0wOxAxiZw&hl=en&sa=X&oi=book_result&resnum=1&ct=result ),좋은 팁은 거기에 차 구현에(항목 9 내가 생각하는...).
내가 선호하는 유틸리티를 사용하여 프롬 방법 Google 컬렉션에 lib 클래스에서는 개체 는록 하는데 도움이 됩니다.매우 자주 equals
고 hashcode
방법은 IDE 의 템플릿,그래서 그들은 청소하지 않습니다.
내가 사용하는 작은 래퍼 Arrays.deepHashCode(...)
처리하기 때문에 배열로 제공되는 매개 변수를 올바르
public static int hash(final Object... objects) {
return Arrays.deepHashCode(objects);
}
여기에는 다른 JDK1.7+접근 방식 시연과 함께 수퍼 클래스 로직 를 차지.내가 그것으로 예쁜 convinient 개체 클래스의 차()를 차지했고,순수하는 JDK 의존성과 별도의 설명서 작동합니다.참고 Objects.hash()
null 관대하다.
나는 포함하지 equals()
구현 하지만 현실에서 당신은 물론 필요합니다.
import java.util.Objects;
public class Demo {
public static class A {
private final String param1;
public A(final String param1) {
this.param1 = param1;
}
@Override
public int hashCode() {
return Objects.hash(
super.hashCode(),
this.param1);
}
}
public static class B extends A {
private final String param2;
private final String param3;
public B(
final String param1,
final String param2,
final String param3) {
super(param1);
this.param2 = param2;
this.param3 = param3;
}
@Override
public final int hashCode() {
return Objects.hash(
super.hashCode(),
this.param2,
this.param3);
}
}
public static void main(String [] args) {
A a = new A("A");
B b = new B("A", "B", "C");
System.out.println("A: " + a.hashCode());
System.out.println("B: " + b.hashCode());
}
}
표준을 구현하는 것은 약하고 그것을 사용하여 이르는 불필요한 충돌 사고로 이어질 수 있습니다.상
class ListPair {
List<Integer> first;
List<Integer> second;
ListPair(List<Integer> first, List<Integer> second) {
this.first = first;
this.second = second;
}
public int hashCode() {
return Objects.hashCode(first, second);
}
...
}
지금
new ListPair(List.of(a), List.of(b, c))
고
new ListPair(List.of(b), List.of(a, c))
동 hashCode
, 즉 31*(a+b) + c
으로 승수 위해 사용됩 List.hashCode
재사용옵니다 여기에.물론,충돌을 피할 수 있지만,그 생산없이에 충돌이 단지...필요하다.
아무것도 없는 실질적으로 스마트 사용에 관하여 31
.승수가 홀수이어야에서 손실을 방지하기 위해 정보(어떤 심지어 배율을 잃은 적어도 가장 중요한 비트,배수의 네 개의 두 가지를 잃고,etc.).어떤 이상한 배율을 사용할 수 있습니다.작은 승으로 이어질 수 있습 빠르게 연산(JIT 사용할 수 있는 교대 및 추가),하지만 주어진 것을 곱하기에는 대기 시간의 사이클에 현대적인 Intel/AMD,이는 거의 문제입니다.작은 승도 더 충돌에 대한 작은 입력에 문제가 될 수 있는 때때로.
를 사용하여 주는 의미로 소수에서 의미가 없습니다 링 Z/(2**32).
그래서 이 사용하는 것이 좋습 무작위로 선택된 큰 홀수(을 주시기 바랍 프라임).로 i86/amd64Cpu 사용할 수 있는 짧은 명령어를 피연산자 피팅에서 하나의 서명된 바이트가있는 작은 속도가 장점에 대한 승 같은 109.을 최소화 하기 위한 충돌,무언가를 가지고 다음과 같 0x58a54cf5.
를 사용하여 다른 곱셈기 다른 장소에서 유용하지만,충분하지 않을 정당화하는 작업이 요구됩니다.
를 결합하는 경우 해쉬값,일반적으로 사용하여 결합하는 방법에 사용되는 부 c++라이브러리,즉:
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
이것이 상당히 좋은 직장을 보장하는 고른 분포를 보여준다.에 대한 논의의 방법 이 수식의 작동,보의 유래 post: 마법수에서 부스트::hash_combine
좋은 토론의 다른 해쉬 기능: http://burtleburtle.net/bob/hash/doobs.html
에 대한 간단한 클래스에 그것은 종종 쉽게 구현하는 차()를 기반으로 클래스에있는 필드가에 의해 확인 equals()구현합니다.
public class Zam {
private String foo;
private String bar;
private String somethingElse;
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Zam otherObj = (Zam)obj;
if ((getFoo() == null && otherObj.getFoo() == null) || (getFoo() != null && getFoo().equals(otherObj.getFoo()))) {
if ((getBar() == null && otherObj. getBar() == null) || (getBar() != null && getBar().equals(otherObj. getBar()))) {
return true;
}
}
return false;
}
public int hashCode() {
return (getFoo() + getBar()).hashCode();
}
public String getFoo() {
return foo;
}
public String getBar() {
return bar;
}
}
가장 중요한 것은 유지하는 것입 차()및 equals()일관된:는 경우 equals()true 를 반환하는 두 개체에 대해 다음의 차()한다 같은 값을 반환합니다.는 경우 equals()가 false 를 반환한 다음의 차()반환해야 합니다 다른 값입니다.