2017-10-16 2 views
0

조슈아 블로흐는 효과적인 자바 말한다 :재정의 해시 코드() 메소드

당신은) (등호를 우선 모든 클래스에 해시 코드를() 재정의해야합니다. 그렇게하지 않으면 Object.hashCode()에 대한 일반 계약 을 위반하게되어 HashMap, HashSet 및 Hashtable을 포함한 모든 해시 기반 모음과 함께 이 제대로 작동하지 않게됩니다.

public class Match { 

    private String homeTeam; 

    private String awayTeam; 

    public Match(String homeTeam, String awayTeam) { 
     this.homeTeam = formatTeamName(homeTeam); 
     this.awayTeam = formatTeamName(awayTeam); 
    } 
} 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 
     Match that = (Match) o; 

     final int threshold = 6; 

     return (computeFuzzyScore(this.homeTeam, that.awayTeam) <= threshold || computeFuzzyScore(this.awayTeam, that.homeTeam) <= threshold) && 
        computeFuzzyScore(this.homeTeam, that.homeTeam) > threshold && computeFuzzyScore(this.awayTeam, that.awayTeam) > threshold; 

    } 

    // formatTeamName(), computeFuzzyScore() have been left out for brevity. 
} 

이러한 개체가 동일한이 방법 :

Match match0 = new Match("Man.City", "Atl.Madryt"); 
Match match1 = new Match("Manchester City", "Atlético Madryt"); 

내가 같은 값을 생성 hashCode() 메소드를 오버라이드 (override)하는 방법

내 오버라이드 (override) equals() 방법은 Match 객체를 비교하는 퍼지 점수 알고리즘을 구현 그런 물건들?

+2

'match0'과'match'는 동일하지 않습니다. 그래서 그들은 최적으로 hashCode()를 가질 필요가 없다. 당신의'equals()'도'true'를 반환하지 않아야합니다. –

+1

hashcode 문서에서 해시 코드는 동등한 인스턴스에 대해 동일해야하지만 다른 인스턴스에 대해서도 동일해야합니다. hashcode는'equals'에서 사용 된 변수만을 사용해야한다는 것을 의미합니다. – AxelH

+0

아마도 'equals'와 같은 구현을 사용하는 것은 좋지 않을 것입니다. 이'equals' 구현체를 커스텀 코드에서만 사용하려고합니까, 아니면 표준 JDK 클래스가'equals' 메소드를 호출 할 것으로 기대합니까? – Eran

답변

2

일치하는 유효한 32 비트 정수 같은 (모든 시간을 전환하고 어떤 결과가 사용 되든 관계없이 코드에서 동일한 결과를 렌더링 할 수 있어야합니다).

이 문제를 해결하는 한 가지 방법은 Remove duplicates from a list of objects based on property in Java 8에 대한 답변에서 설명한 래퍼 클래스를 사용하는 것입니다. 래퍼 클래스가 계산 된 퍼지 값만 저장하고 equals와 hashcode의 값을 비교하여 사용하면 unwrapp를 사용하여 실제 값을 얻을 수 있습니다.

또 다른 방법은 yshavit 말한 것처럼 할 및 문자열에 다른 동일 유사한 작업을 수행하는 것입니다 : 당신은 fuzzyEquals 대신 equals으로 다른 방법 이름을 사용하는 것이 좋습니다

+0

'Match.equals()'메소드를 strict로 만들고, 퍼지 비교를 위해'Match.isSimilarTo()'라는 또 다른 메소드를 제안했습니다. – TheChosenOne

+0

좋은 해결책 같네요. – Jotunacorn

0

match1 == match2 다음에 match1.hashCode() == match2.hashCode() 인 경우 중요한 부분입니다. ID (숫자)와 일치하는 것을 저장하는 데이터베이스가 있다고 가정하면 hashCode에 ID를 반환하고 완료 할 수 있습니다.

일치하는 ID를 추적하기 위해 데이터베이스를 사용하지 않고 모든 팀에 고정 길이의 숫자 ID를 할당하고 hashCode의 결과로 두 ID를 연결합니다.

예를 들어 "Manchester City" 팀은 팀 1"Atlético Madryt"2 일 수 있습니다. 해시가 32 비트이면 첫 번째 16 비트를 팀 1, 마지막 16을 팀 2과 같이 표현할 수 있습니다.

// 16 bit for team 1 + 16 bit for team 2 
0000000000000001  0000000000000010 

이 동일에만있는 객체에 대해 true를 반환해야 다음 match1 == match2의 규칙 M. 르 RUTTE 이미 AxelH 말에 의해 답변으로 match1.hashCode() == match2.hashCode()

+0

각 인스턴스에'id'를 추가하면 작동하지만'Map'은 인스턴스마다 버킷을 생성합니다 (기본적으로 해시 코드를 사용하여 버킷을 주문하기 때문에). – AxelH

1

을 equalsIgnoreCase. 용도에 따라 hashCodeequals을 확인해야합니다. HashMap과 같은 많은 Java 클래스는 사용자의 동의없이이 두 메서드를 호출하고 해당 메서드를 엄격하게 준수하도록 요구합니다. 그리고 그들의 생각은 당신이 원하는 것이 아니라 그들이 필요로하는 것입니다.그것은이 같은 뭔가 :

  • 는 =의 homeTeam.equals & & awayTeam.equals 동일 = homeTeam.hashCode^awayTeam.hashCode는

이름을 변경함으로써, 사용자는 (a)의 HashMap 및 유지

  • 해시 코드 그의 (b) 혼란을 피하십시오. (c) 가독성을 높이고 (d) 서로 다른 두 가지 방법을 사용할 수 있습니다.이 두 가지 방법은 독립적으로 사용하거나 더 결합 할 수 있습니다.

  • 1

    완료하려면 데이터 모델을 검토해야합니다. 그것은

    • MatchTeam 사이에 순간 당신에 실패한 것입니다.
    • Teamname
    • 을 가지고 Teamalias (0..N)를 갖는다.

    당신은 같은 somethink 것 :

    public Team{ 
    
        private final String name; 
        private List<String> alias; 
    
        public Team(Sting name){ ... } 
    
        public boolean equals(Object obj){ 
         // check name 
        } 
    
        public int hashCode(){ 
         // hash the name 
        } 
    } 
    

    그런 다음, 바로이 클래스 같은 방법을 사용하는 Match을 검토합니다.

    클래스 Teamalias에서 발견/일치하지 않는, 그것은 당신의 너 한테를 사용하여 name에 문의 할 경우 String 일치하는 별칭을 확인하는 방법을 제공 할 수있다. 이 alias이 일치하면 미래 연구를 위해 List에 추가하십시오.

    그런 식으로 매번 퍼지 알고리즘을 실행할 필요가 없습니다. 사용자가 자신이 선택한 입력과 일치하는 Team을 얻으려면 유용 할 수 있습니다.