컬렉션의 hashCode 메서드에 대한 최적의 구현
「 」의 됩니까?hashCode()
- 수집 메서드(수집 메서드)에 대한 설명
최적의 구현?그것은 사용 패턴에 따라 다르기 때문에 어려운 질문입니다.
거의 모든 경우에 대한 합리적인 양호한 구현은 항목 8(제2판)의 Josh Bloch의 Effective Java에서 제안되었습니다.저자가 왜 접근법이 좋은지 설명해주기 때문에 거기서 찾아보는 것이 가장 좋다.
짧은 버전
작성하다
int result
0이 아닌 값을 할당합니다.모든 분야에 대하여
f
에서 되었습니다.equals()
, "" "" " " " " " " " "c
삭제:- 가 "f" a"인
boolean
: 산산(f ? 0 : 1)
; - 가 "f" a"인
byte
,char
,short
★★★★★★★★★★★★★★★★★」int
: 산산(int)f
; - 가 "f" a"인
long
: 산산(int)(f ^ (f >>> 32))
; - 가 "f" a"인
float
: 산산Float.floatToIntBits(f)
; - 가 "f" a"인
double
: 산산Double.doubleToLongBits(f)
모든 긴 값과 마찬가지로 리턴 값을 처리합니다. - 필드 f가 오브젝트인 경우:의 결과를 사용합니다.
hashCode()
method '0'(메서드 '0'의 경우)f == null
; - 필드 f가 배열인 경우: 각 필드를 개별 요소로 보고 해시 값을 재귀적으로 계산하고 다음에 설명된 값을 결합합니다.
- 가 "f" a"인
" " " 를 합니다.
c
result
:result = 37 * result + c
result
이로 인해 대부분의 사용 상황에서 해시 값이 올바르게 분포됩니다.
dmeister가 추천하는 효과적인 Java 구현에 만족하는 경우, 직접 롤하는 대신 라이브러리 호출을 사용할 수 있습니다.
@Override
public int hashCode() {
return Objects.hashCode(this.firstName, this.lastName);
}
에는 구아바Guava)가합니다.com.google.common.base.Objects.hashCode
7 7)의 표준 라이브러리('Java 7')입니다java.util.Objects.hash
는 같은
문서(Wayback Machine)와 Github의 My own code에 링크되어 있지만 Java에서는 일반적으로 동작합니다.제 답변은 dmeister's Answer와 읽기 쉽고 이해하기 쉬운 코드를 확장한 것입니다.
@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));
}
Eclipse가 제공하는 기능을 사용하는 것이 좋습니다.이 기능은 매우 훌륭하고 비즈니스 로직 개발에 노력과 에너지를 쏟을 수 있습니다.
우선 동등성이 올바르게 구현되어 있는지 확인합니다.IBM DeveloperWorks 기사:
- 대칭:a와 b, a.equals(b)가 b.equals(a)인 경우만
- 반사성:null이 아닌 모든 참조의 경우 a.equals(a)
- 이동성:a.equals(b) 및 b.equals(c)일 경우 a.equals(c)
그런 다음 hashCode와의 관계가 (같은 기사의) 컨택을 존중하는지 확인합니다.
- hashCode()와의 일관성:동일한 두 개체의 hashCode() 값은 같아야 합니다.
마지막으로 양호한 해시함수는 이상적인 해시함수에 접근하기 위해 노력해야 합니다.
about8.blogspot.com 라고 말씀하셨습니다.
equals()가 true를 반환하는 경우 hashCode()는 동일한 값을 반환해야 합니다.equals()가 false를 반환하는 경우 hashCode()는 다른 값을 반환해야 합니다.
난 자네 의견에 동의할 수 없거든.두 개체의 해시 코드가 같을 경우 동일한 해시 코드를 의미할 필요가 없습니다.
A가 B와 같을 경우 A.hashcode는 B.hascode와 같아야 합니다.
그렇지만
A.hashcode가 B.hascode와 같을 경우 A가 B와 같아야 한다는 의미는 아닙니다.
하면 ★★★★★★★★★★★★★★★★★」equals()
★★★★★★★★★★★★★★★★★」hashCode()
라이선스:
소스 -> hashCode() 및 equals()를 생성합니다.
이 함수를 사용하여 등식 및 해시 코드 계산에 사용할 필드를 결정할 수 있으며, 이클립스는 해당 메서드를 생성합니다.
효과적인 Java가 적절하게 구현되어 있습니다.hashcode()
★★★★★★★★★★★★★★★★★」equals()
Apache Commons Lang의 로직.HashCodeBuilder 및 EqualsBuilder를 확인합니다.
기타 상세 답변을 작성하기 위한 간단한 메모(코드 용어):
how-do-i-create-a-hash-table-in-java, 특히 jGuru FAQ 엔트리를 고려한다면 해시 코드를 판단할 수 있는 다른 기준은 다음과 같습니다.
- synchronization(동시접속 지원 여부)
- fail safe repeating(반복 중에 변경되는 컬렉션을 algo가 검출합니까)
- null value(해시 코드가 컬렉션의 null 값을 지원합니까)
질문을 올바르게 이해하면 커스텀 컬렉션 클래스(즉, Collection 인터페이스에서 확장되는 새로운 클래스)가 있고 hashCode() 메서드를 구현하려고 합니다.
컬렉션 클래스가 AbstractList를 확장하면 걱정할 필요가 없습니다.equals()와 hashCode()의 실장은 이미 모든 오브젝트를 반복하여 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);
}
@about 8 : 꽤 심각한 버그가 있습니다.
Zam obj1 = new Zam("foo", "bar", "baz");
Zam obj2 = new Zam("fo", "obar", "baz");
동일 해시 코드
당신은 아마 이런 것을 원할 것이다
public int hashCode() {
return (getFoo().hashCode() + getBar().hashCode()).toString().hashCode();
(요즘 Java에서 int에서 hash Code를 직접 얻을 수 있습니까?자동 주조 기능이 있는 것 같은데..이 경우 toString은 건너뛰세요.추측합니다.)
수집을 요청하신 것처럼, 다른 답변에서는 아직 언급하지 않은 측면을 추가하고 싶습니다.HashMap은 키가 컬렉션에 추가되면 해시 코드가 변경되지 않을 것으로 예상합니다.모든 목적을 망칠 수도 있고
Apache Commons Equals Builder 및 HashCode Builder에서 반사 메서드를 사용합니다.
파라미터로 제공된 어레이를 올바르게 처리하기 때문에 작은 래퍼를 사용합니다.
public static int hash(final Object... objects) {
return Arrays.deepHashCode(objects);
}
해시 값을 가능한 범위로 균등하게 분산하는 해시 방식은 모두 적절한 구현입니다.효과적인 자바(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는...).
코드를 깨끗하게 유지하는 데 도움이 되는 Class Objects의 Google Collections lib 유틸리티 메서드를 사용하는 것이 좋습니다.자주equals
그리고.hashcode
메서드는 IDE의 템플릿에서 생성되므로 읽기에는 깨끗하지 않습니다.
슈퍼클래스의 로직을 사용한 JDK 1.7+ 어프로치의 데모를 다음에 나타냅니다.오브젝트 클래스 hashCode() 어카운트, 순수 JDK 의존성, 추가 수동 작업 없이 매우 편리하다고 생각합니다.부디 참고하세요Objects.hash()
늘 톨러런스입니다.
나는 아무것도 포함하지 않았다.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
정보 손실을 피하기 위해 곱셈기는 홀수여야 합니다(짝수 곱셈기는 적어도 최상위 비트를 잃거나 4의 배수는 2를 잃는 등).을 사용법수가가((((((((((((J)IT부문의 기술입니다.다만, 현대의 인텔/AMD에서는 곱셈의 레이텐시가 3 사이클 밖에 되지 않기 때문에, 이것은 거의 문제가 되지 않습니다.승수가 작을수록 입력이 작을수록 충돌이 심해지므로 때로는 문제가 될 수 있습니다.
소수는 링 Z/(2**32)에서 의미가 없기 때문에 소수를 사용하는 것은 의미가 없습니다.
그래서 무작위로 큰 홀수를 선택하는 것을 추천합니다(마이너스도 부담없이).i86/amd64 CPU는 단일 부호 바이트의 오퍼랜드 피팅에 대해 짧은 명령을 사용할 수 있기 때문에 109와 같은 곱셈기에는 아주 작은 속도의 이점이 있습니다.충돌을 최소화하려면 0x58a54cf5와 같은 것을 취하십시오.
서로 다른 장소에서 다른 승수를 사용하는 것은 도움이 되지만, 추가 작업을 정당화하기에는 충분하지 않을 수 있습니다.
해시 값을 조합할 때는 보통 boost c++ 라이브러리에서 사용되는 조합 방법을 사용합니다.즉, 다음과 같습니다.
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
이는 균등한 분배를 보장하는 데 매우 효과적입니다.이 계산식의 기능에 대한 자세한 내용은 StackOverflow post: Magic number in boost를 참조하십시오.: syslog_syslogs
다양한 해시 함수에 대한 자세한 내용은 http://burtleburtle.net/bob/hash/doobs.html에서 확인할 수 있습니다.
단순한 클래스의 경우 equals() 구현에 의해 체크되는 클래스 필드에 따라 hashCode()를 구현하는 것이 가장 쉽습니다.
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;
}
}
가장 중요한 것은 hashCode()와 equals()를 일관되게 유지하는 것입니다.equals()가 true를 반환하는 경우 hashCode()는 같은 값을 반환해야 합니다.equals()가 false를 반환하는 경우 hashCode()는 다른 값을 반환해야 합니다.
언급URL : https://stackoverflow.com/questions/113511/best-implementation-for-hashcode-method-for-a-collection
'programing' 카테고리의 다른 글
java의 각 루프에 대해 역순으로 할 수 있습니다. (0) | 2022.08.13 |
---|---|
VueJS 앱 내에서 VuePress 문서에 액세스하시겠습니까? (0) | 2022.08.13 |
C 포인터에 직접 값 할당 (0) | 2022.08.13 |
텍스트 상자에 입력하는 동안 목록 검색 VueJs (0) | 2022.08.13 |
Vuex 및 VueJs(변환 핸들러 외부에 있는 vuex 스토어 상태를 변환하지 마십시오) (0) | 2022.08.13 |