Java에서 equals 및 hashCode 메소드를 대체해야하는 이유는 무엇입니까?


383

최근에이 Developer Works Document를 읽었습니다 .

이 문서는 정의 hashCode()하고 equals()효과적이고 정확하게 작성 하는 데 관한 것이지만, 왜이 두 가지 방법을 재정의해야하는지 알 수 없습니다.

이러한 방법을 효율적으로 구현하기로 결정하려면 어떻게해야합니까?


4
programming.guide에는 정확히 이것을 설명하는 두 가지 훌륭한 기사가 있습니다. 같음을 무시 왜 당신은 항상 해시 코드를 오버라이드 (override) 할 필요가 있습니다 . (경고 한 답변은 실제로 틀 렸습니다.)
aioobe

Case Override는 다음과 같습니다. 두 개의 동일한 객체에는 다른 해시 코드가 있습니다 = 동일한 객체는 다른 버킷에 있습니다 (중복). Case Override (해시 코드 만) : 두 개의 동일한 객체에 동일한 해시 코드 = 동일한 객체가 동일한 버킷에 있습니다 (중복).
VdeX

답변:


524

Joshua Bloch는 효과적인 Java에 대해 말합니다.

equals ()를 재정의하는 모든 클래스에서 hashCode ()를 재정의해야합니다. 그렇게하지 않으면 Object.hashCode ()에 대한 일반 계약을 위반하게되어 클래스가 HashMap, HashSet 및 Hashtable을 포함한 모든 해시 기반 컬렉션과 함께 제대로 작동하지 못하게됩니다.

재정의 equals()하지 않고 재정의하고을 hashCode()사용하려고 시도 하면 어떻게 될지에 대한 예를 통해 이해하려고합시다 Map.

우리는이 같은 클래스를 가지고 두 객체가 있다고 MyClass자신의 경우 동일 importantFieldIS는 (와 동일 hashCode()하고 equals()일식에 의해 생성)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

무시 만 equals

equals재정의 된 경우에만 myMap.put(first,someValue)처음 호출 하면 일부 버킷으로 myMap.put(second,someOtherValue)해시되고 다른 버킷으로 다른 버킷으로 해시됩니다 hashCode. 따라서 동일한 버킷에 해시하지 않으므로 동일하지만 맵은이를 인식 할 수 없으며 둘 다 맵에 유지됩니다.


재정의 equals()하면 재정의 할 필요는 없지만 hashCode(), 두 MyClass경우 importantField가 동일하지만 재정의하지 않으면 이 두 개체 가 동일한 것을 알고있는이 특별한 경우에 어떤 일이 발생하는지 봅시다 equals().

무시 만 hashCode

당신이 이것을 상상해보십시오

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

재정의 hashCode한 다음 호출 myMap.put(first,someValue)할 때 먼저 걸리면 계산합니다.hashCode 주어진 버킷에 저장합니다. 그런 다음 전화 myMap.put(second,someOtherValue)할 때 비즈니스 요구 사항에 따라 동일하므로 맵 문서에 따라 첫 번째로 두 번째로 바꿔야 합니다.

그러나 문제는지도 해시 그렇게 할 때, 등호 재정의되지 않은 것입니다 second오브젝트가있는 경우 버킷 통해 반복보고 k그러한second.equals(k) 이 같은 하나를 찾을 수 없습니다 사실이다 second.equals(first)될 것입니다 false.

분명했으면 좋겠다


5
두 번째 경우 왜 두 번째 객체가 다른 버킷에 들어가야하는지 좀 더 자세히 설명해 주시겠습니까?
Hussain Akhtar Wahid 'Ghouri'5

57
이 답변은 마음에 들지 않습니다. equals ()를 재정의하지 않고 hashCode ()를 재정의 할 수 없음을 제안하기 때문에이 답변이 마음에 들지 않습니다. 두 객체를 동일하게 정의 하기 때문에 예제 코드 ( "override only hashCode"부분)가 작동하지 않지만 미안합니다.이 정의는 머리에만 있습니다. 첫 번째 예에서는 동일한 hashCode를 가진 두 개의 같지 않은 객체가 있으며 이는 완전히 합법적입니다. 따라서 equals ()를 재정의해야하는 이유는 이미 hashCode ()를 재정의했기 때문이 아니라 "같음"정의를 머리에서 코드로 옮기려고하기 때문입니다.
user2543253

11
if you think you need to override one, then you need to override both of them잘못되었습니다. hashCode클래스가 재정의 equals되지만 역이 아닌 경우 재정의해야 합니다.
akhil_mittal

4
나는 그것이 완전히 생각 ()는 해시 코드를 오버라이드 (override) 확인 뿐만 아니라 () 등호를 무시하지 않고. 또한 Effective Java로 작성된 내용 : books.google.fr/…
Johnny

2
@PhantomReference, 재정의만 equals이 javadoc에 명시된 계약을 위반 한다는 점에 유의하십시오 Object. "두 개의 오브젝트가 equals(Object)메소드 에 따라 동일하면 두 오브젝트 hashCode각각에 대해 메소드 를 호출 하면 동일한 정수 결과가 생성되어야합니다." 물론, 모든 계약의 모든 부분이 모든 코드에서 실행되는 것은 아니지만 공식적으로는 위반으로 간주되며, 버그가 발생하기를 기다리는 버그라고 생각합니다.
aioobe

263

개체 의 해시 코드HashMap과 같은 컬렉션을 HashSet사용하여 컬렉션 내에 개체를 저장하는 방법을 결정하고 컬렉션 에서 개체를 찾기 위해 해시 코드 를 다시 사용합니다.

해싱 검색은 2 단계 프로세스입니다.

  1. 올바른 버킷 찾기 ( hashCode())
  2. 버킷을 사용하여 올바른 요소 검색 ( equals())

여기에 우리가 설정을 무시해야하는 이유에 작은 예입니다 equals()hashcode().

Employee나이와 이름이라는 두 가지 필드가 있는 수업을 생각해보십시오 .

public class Employee {

    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

이제 클래스를 만들고에 Employee객체를 삽입 HashSet하고 해당 객체가 있는지 여부를 테스트하십시오.

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

다음을 인쇄합니다.

false
employee.hashCode():  321755204  employee2.hashCode():375890482

이제 uncomment hashcode()method, 동일하게 실행하면 출력은 다음과 같습니다.

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

이제 두 객체가 같은 것으로 간주되면 해시 코드도 같아야하는 이유를 알 수 있습니까? 그렇지 않으면 두 개 이상의 객체가 동일한 것으로 간주되는 방식으로 메서드를 재정의 하더라도 Object 클래스 의 기본 해시 코드 메소드는 사실상 각 객체에 대해 항상 고유 번호를 갖기 때문에 객체를 찾을 수 없습니다. equals(). 해시 코드 가 그것을 반영하지 않으면 객체가 얼마나 동일한 지 중요 하지 않습니다. 따라서 한 번 더 : 두 객체가 같으면 해시 코드 도 같아야합니다.


4
완벽한 예입니다. 차이점을 분명히 보여주었습니다!
coderpc

3
좋은 설명 @rajeev
VdeX

2
@VikasVerma equals 객체는 동일한 해시 코드를 가지지 만, 동일하지 않은 객체가 다른 해시 코드를 갖는 것은 아닙니다. 객체가 실제로 다르지만 해시 코드가 동일하면 어떻게됩니까?
Ravi

1
:)
Rahul

4
받아 들여진 대답보다 훨씬 더 나은 대답! 감사
유목

50

equals ()를 재정의하는 모든 클래스에서 hashCode ()를 재정의해야합니다. 그렇게하지 않으면 Object.hashCode ()에 대한 일반 계약을 위반하게되어 클래스가 HashMap, HashSet 및 Hashtable을 포함한 모든 해시 기반 컬렉션과 함께 제대로 작동하지 못하게됩니다.


   에서 효과적인 자바 조슈아 블로흐,

정의 equals()하고 hashCode()일관되게 클래스의 유용성을 해시 기반 컬렉션의 키로 향상시킬 수 있습니다. hashCode에 대한 API 문서에서 설명하는 것처럼 "이 메소드는에서 제공하는 것과 같은 해시 테이블의 이점을 위해 지원됩니다 java.util.Hashtable."

이러한 메소드를 효율적으로 구현하는 방법에 대한 귀하의 질문에 대한 최선의 답변은 효과적인 Java의 3 장을 읽는 것 입니다.


4
이것이 정답입니다. 물론 해시 기반 컬렉션에서 클래스를 사용하지 않으면 구현하지 않은 것은 중요하지 않습니다 hashCode().
슬림

1
더 복잡한 경우에는 사용하는 컬렉션이 해시를 사용하는지 알 수 없으므로 "hashCode ()를 구현하지 않았다는 것은 중요하지 않습니다"
Victor Sergienko

1
equals ()를 재정의하지 않고 hashCode ()를 재정의 할 수 있습니까?
Johnny

@StasS는 예, 허용 된 답변의 내용과 반대입니다. 이 기사의 두 번째 부분에서 설명을 참조하십시오. equals를 재정의 할 때 항상 hashCode를 재정의해야하는 이유
aioobe

22

간단히 말해 Object의 equals-method는 참조가 동일한 지 확인합니다. 여기서 속성이 같을 때 클래스의 두 인스턴스가 의미 론적으로 동일 할 수 있습니다. 예를 들어 HashMapSet 과 같이 equals 및 hashcode를 사용하는 컨테이너에 객체를 넣을 때 중요합니다 . 다음과 같은 클래스가 있다고 가정 해 봅시다.

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

동일한 ID로 두 개의 인스턴스를 만듭니다 .

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

동등성을 재정의하지 않으면 다음과 같은 결과를 얻습니다.

  • a.equals (b)는 서로 다른 두 인스턴스이므로 false입니다.
  • a.equals (a)는 동일한 인스턴스이므로 true입니다.
  • b.equals (b)는 동일한 인스턴스이므로 true입니다.

옳은? 아마도 이것이 당신이 원하는 것이라면 어쩌면. 그러나 두 개의 다른 인스턴스인지 여부에 관계없이 동일한 ID를 가진 객체가 동일한 객체가되기를 원한다고 가정 해 봅시다. 우리는 equals (및 해시 코드)를 재정의합니다.

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

equals와 hashcode 구현에 관해서는 Guava의 도우미 메소드를 사용하는 것이 좋습니다.


20

정체성은 평등이 아닙니다.

  • 운영자 ==테스트 ID 와 같습니다 .
  • equals(Object obj) 방법은 평등 테스트를 비교합니다 (즉, 우리는 방법을 재정 의하여 평등을 알려야합니다)

Java에서 equals 및 hashCode 메소드를 대체해야하는 이유는 무엇입니까?

먼저 equals 메소드의 사용법을 이해해야합니다.

두 객체 간의 차이점을 식별하려면 equals 메소드를 재정의해야합니다.

예를 들면 다음과 같습니다.

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

이제 hashCode 메소드는 쉽게 이해할 수 있습니다.

hashCode는 HashMap , HashSet 과 같은 데이터 구조에 객체를 저장하기 위해 정수를 생성합니다 .

Customer위와 같은 재정의 equals 메소드를 가지고 있다고 가정합니다 .

customer1.equals(customer2);  // returns true by our own logic

버킷에 객체를 저장할 때 데이터 구조로 작업하는 동안 (버킷은 폴더의 멋진 이름입니다). 내장 해시 기술을 사용하면 위의 두 고객에 대해 두 개의 다른 해시 코드가 생성됩니다. 그래서 우리는 동일한 동일한 객체를 서로 다른 두 곳에 저장하고 있습니다. 이러한 종류의 문제를 피하려면 다음 원칙에 따라 hashCode 메서드를 재정의해야합니다.

  • 동일하지 않은 인스턴스는 동일한 해시 코드를 가질 수 있습니다.
  • 동일한 인스턴스는 동일한 해시 코드를 반환해야합니다.

3
지난 1 시간 이후 내가 찾던 것입니다. 멋진 친구 (y)
Adnan

13

좋아요, 개념을 아주 간단한 단어로 설명하겠습니다.

먼저 더 넓은 관점에서 우리는 컬렉션을 가지고 있으며 해시 맵은 컬렉션의 데이터 구조 중 하나입니다.

해시 맵이 무엇인지 그리고 무엇을 먼저 이해해야하는 경우 equals 및 hashcode 메소드를 모두 대체해야하는 이유를 이해하려면.

해시 맵은 키 값의 데이터 쌍을 배열 방식으로 저장하는 데이터 구조입니다. a []를 말하자. 여기서 'a'의 각 요소는 키 값 쌍입니다.

또한, 상기 어레이의 각 인덱스는 링크 된리스트 일 수 있으며, 이에 의해 하나의 인덱스에서 하나 이상의 값을 가질 수있다.

왜 해시 맵이 사용됩니까? 큰 배열 중에서 검색 해야하는 경우 효율적이지 않은 경우 각 배열을 검색해야하므로 해시 기술에 따르면 배열을 일부 논리로 사전 처리하고 해당 논리에 따라 요소를 그룹화 할 수 있습니다.

예 : 배열 1,2,3,4,5,6,7,8,9,10,11이 있고 해시 함수 mod 10을 적용하여 1,11이 함께 그룹화됩니다. 따라서 이전 배열에서 11을 검색해야하는 경우 전체 배열을 반복해야하지만 그룹화 할 때 반복 범위를 제한하여 속도를 향상시킵니다. 위의 모든 정보를 저장하는 데 사용되는 데이터 구조는 단순화를 위해 2D 배열로 생각할 수 있습니다.

이제 위의 해시 맵과 별도로 중복을 추가하지 않는다고 알려줍니다. 그리고 이것이 equals와 hashcode를 재정의 해야하는 주된 이유입니다.

따라서 hashmap의 내부 작업을 설명한다고 말하면 해시 맵이 어떤 메소드를 가지고 있고 위에서 설명한 위의 규칙을 어떻게 준수하는지 찾아야합니다.

따라서 해시 맵에는 put (K, V)이라는 메소드가 있으며 해시 맵에 따르면 배열을 효율적으로 분배하고 중복을 추가하지 않는 위의 규칙을 따라야합니다

따라서 넣은 것은 먼저 주어진 키에 대한 해시 코드를 생성하여 값을 가져갈 인덱스를 결정합니다. 해당 인덱스에 아무것도 없으면 새 값이 추가됩니다. 그런 다음 해당 색인에서 링크 된 목록의 끝에 새 값을 추가해야합니다. 그러나 원하는 해시 맵 동작에 따라 복제본을 추가해서는 안됩니다. 두 개의 Integer 객체 aa = 11, bb = 11이 있다고 가정하겠습니다. 객체 클래스에서 파생 된 모든 객체와 마찬가지로 두 객체를 비교하는 기본 구현은 객체 내부의 값이 아니라 참조를 비교하는 것입니다. 따라서 위의 경우 의미 론적으로 동일하더라도 동등성 테스트에 실패하고 동일한 해시 코드와 동일한 값을 갖는 두 개의 객체가 존재할 가능성이 있으므로 중복이 생성됩니다. 재정의하면 중복 추가를 피할 수 있습니다. 당신은 또한 참조 할 수 있습니다세부 작업

import java.util.HashMap;


public class Employee {

String name;
String mobile;
public Employee(String name,String mobile) {
    this.name=name;
    this.mobile=mobile;
}

@Override
public int hashCode() {
    System.out.println("calling hascode method of Employee");
    String str=this.name;
    Integer sum=0;
    for(int i=0;i<str.length();i++){
        sum=sum+str.charAt(i);
    }
    return sum;

}
@Override
public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    System.out.println("calling equals method of Employee");
    Employee emp=(Employee)obj;
    if(this.mobile.equalsIgnoreCase(emp.mobile)){

        System.out.println("returning true");
        return true;
    }else{
        System.out.println("returning false");
        return false;
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Employee emp=new Employee("abc", "hhh");
    Employee emp2=new Employee("abc", "hhh");
    HashMap<Employee, Employee> h=new HashMap<>();
    //for (int i=0;i<5;i++){
        h.put(emp, emp);
        h.put(emp2, emp2);

    //}

    System.out.println("----------------");
    System.out.println("size of hashmap: "+h.size());


}

}

혼동이 있는데 HashMap의 경우 hashCode 메서드를 재정의 할 때 equals 메서드를 재정의 해야하는 이유는 무엇입니까? 어쨌든 해시 맵은 객체의 해시 코드가 같으면 값을 대체합니다.
Vikas Verma

@VikasVerma 해시 맵은 객체의 해시 코드가 동일한 경우 어떤 종류의 값도 대체하지 않으며, 해시 맵에 새로 추가 된 객체를 배치 할 인덱스 만 결정합니다. 이제 인덱스에 객체가있을 수 있으므로 중복을 피하기 위해 equals 메서드를 재정의하고 비교할 두 객체를 동일하게 처리 할시기를 정의하는 논리를 작성합니다. 재정의되지 않으면 동일한 값을 가진 객체가 저장되지만 두 객체의 참조가 다르기 때문에 저장됩니다.
Chetan

11

hashCode() :

해시 코드 방법 만 재정의하면 아무 일도 일어나지 않습니다. hashCode각 객체에 대해 항상 새 클래스를 Object 클래스로 반환하기 때문 입니다.

equals() :

동일한 방법 만 재정의하는 경우 a와 b는 동일하지만 발생하지 않아야 a.equals(b)함을 의미합니다 hashCode. hashCode메소드를 대체하지 않았기 때문 입니다.

참고 : hashCode()Object 클래스의 메소드는 hashCode각 객체에 대해 항상 새로운 것을 반환 합니다.

당신이 해시를 기반으로 컬렉션 개체를 사용해야하는 경우에, 모두 오버라이드 (override) 할 필요가 그래서 equals()hashCode().


hashCode () 만 재정의하는 것에 대한 흥미로운 점 입니다. 괜찮아요? 아니면 문제가 될 수 있습니까?
Johnny

1
오해의 소지가 있습니다. (= only =) hashCode ()를 재정의하면 비슷한 속성을 가진 각 클래스에서 인스턴스화되는 모든 객체가 동일한 해시 코드를 갖도록합니다. 그러나 그들 중 누구도 서로 같지 않기 때문에 유용하지 않습니다.
mfaisalhyder

8

자바는 규칙을

"Object 클래스 equals 메소드를 사용하여 두 오브젝트가 동일한 경우 해시 코드 메소드는이 두 오브젝트에 대해 동일한 값을 제공해야합니다."

따라서 클래스에서 equals()재정의 hashcode()하는 경우이 규칙을 따르도록 메소드 를 재정의해야합니다 . 예를 들어, 키와 값 쌍으로 값을 저장하기 위해 두 가지 방법 equals()hashcode()가 모두 사용됩니다 Hashtable. 우리가 하나를 재정의하고 다른 것을 재정의하지 않으면 Hashtable그러한 객체를 키로 사용하면 원하는대로 작동하지 않을 수 있습니다.


6

당신이 그것들을 무시하지 않으면 당신은 Object의 기본 함침을 사용할 것입니다.

인스턴스 동등성과 hascode 값은 일반적으로 객체를 구성하는 요소에 대한 지식이 필요하므로 일반적으로 클래스에서 유형적 의미를 갖도록 재정의해야합니다.


6

HashMap, Hashtable 등의 컬렉션에서 자체 클래스 객체를 키로 사용하려면 컬렉션의 내부 작업에 대한 인식을 통해 메서드 (hashCode () 및 equals ())를 모두 재정의해야합니다. 그렇지 않으면 예상치 못한 잘못된 결과가 발생합니다.


6

@Lombo의 답변에 추가

언제 equals ()를 재정의해야합니까?

Object의 equals ()의 기본 구현은

public boolean equals(Object obj) {
        return (this == obj);
}

즉, 두 개의 객체가 동일한 메모리 주소를 가진 경우에만 동일한 것으로 간주되며 객체를 자체와 비교하는 경우에만 적용됩니다.

그러나 하나 이상의 속성 값이 동일한 경우 두 객체를 동일하게 고려할 수 있습니다 (@Lombo의 답변에 제공된 예 참조).

따라서 equals()이러한 상황에서 재정의 하고 평등 조건을 스스로 지정할 수 있습니다.

equals ()를 성공적으로 구현했으며 제대로 작동합니다. 왜 hashCode ()를 재정의하도록 요청합니까?

사용자 정의 클래스에서 "해시"기반 컬렉션 을 사용하지 않는 한 괜찮습니다. 하지만 당신은 할 수 있습니다 미래의 어떤 시간을 사용 HashMap하거나 HashSet하지 당신이 할 경우 override해시 코드를 () "제대로 구현" , 이러한 해시 기반의 수집은 아닙니다 작동한다.

재정의는 같음 (@Lombo의 답변에 추가)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

우선 해시 맵의 hashCode가와 second같은지 확인합니다 first. 값이 동일한 경우에만 동일한 버킷에서 동등성을 확인합니다.

그러나 여기서는 hashCode 가이 두 객체에 대해 다릅니다 (기본 구현과 다른 메모리 주소를 가지기 때문에). 따라서 평등을 확인하는 것조차 중요하지 않습니다.

재정의 된 equals () 메소드 내에 중단 점이 있으면 서로 다른 hashCode가있는 경우 들어 가지 않습니다. contains()확인 hashCode()하고 동일한 경우에만 equals()메소드를 호출합니다 .

모든 버킷에서 HashMap이 동일한 지 검사 할 수없는 이유는 무엇입니까? 따라서 hashCode ()를 재정의 할 필요가 없습니다 !!

그런 다음 해시 기반 컬렉션의 요점이 없습니다. 다음을 고려하세요 :

Your hashCode() implementation : intObject%9.

다음은 버킷 형태로 저장된 키입니다.

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

예를 들어지도에 키 10이 포함되어 있는지 알고 싶습니다. 모든 버킷을 검색 하시겠습니까? 또는 하나의 버킷 만 검색 하시겠습니까?

hashCode를 기반으로 10이 있으면 버킷 1에 있어야 함을 식별하므로 버킷 1 만 검색됩니다 !!


5
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • put ( 'key', 'value')는 hashCode()버킷을 결정하는 데 사용하는 해시 값을 계산하고 값을 버킷 equals()에 이미 있는지 여부를 확인하는 방법을 사용 합니다. 그렇지 않으면 다른 값이 추가되고 현재 값으로 대체됩니다
  • get ( 'key')는 hashCode()먼저 항목 (버킷) equals()을 찾고 항목에서 값을 찾는 데 사용합니다.

둘 다 재정의되면

<지도 >

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

equals가 재정의되지 않은 경우

<지도 >

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

hashCode가 재정의되지 않은 경우

<지도 >

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

해시 코드 동일 계약

  1. 동일한 방법에 따라 동일한 두 개의 키는 동일한 hashCode를 생성해야합니다.
  2. 동일한 hashCode를 생성하는 두 키가 같을 필요는 없습니다 (위의 예에서 모든 짝수는 동일한 해시 코드를 생성합니다)

4

양동이에 모두 검은 색으로 공을 모으는 것을 고려하십시오. 당신의 임무는 다음과 같이 공을 색칠하고 적절한 게임에 사용하는 것입니다.

테니스 용-노랑, 빨강. 크리켓 용-화이트

이제 버킷에는 노란색, 빨간색 및 흰색의 세 가지 색상의 공이 있습니다. 그리고 지금 당신은 채색을했습니다. 당신은 어떤 색이 어떤 게임에 적합한 지 아는 것입니다.

공을 색칠-해싱. 게임 공 선택-같음.

당신이 채색을하고 누군가가 크리켓이나 테니스를 위해 공을 선택한다면 그들은 색상을 신경 쓰지 않을 것입니다!


4

설명을 살펴 보았습니다. "hashCode 만 재정의하는 경우 먼저 호출 myMap.put(first,someValue)할 때 해시 코드를 계산하고 지정된 버킷에 저장합니다. 그런 다음 호출 myMap.put(first,someOtherValue)할 때 맵 문서가 동일하므로 두 번째로 대체해야합니다. (우리의 정의에 따라). " :

우리가 추가 할 때 두 번째 시간은 myMap다음과 같은 '두 번째'객체 여야한다고 생각합니다.myMap.put(second,someOtherValue)


4

1) 일반적인 실수는 아래 예에 나와 있습니다.

public class Car {

    private String color;

    public Car(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if(obj==null) return false;
        if (!(obj instanceof Car))
            return false;   
        if (obj == this)
            return true;
        return this.color.equals(((Car) obj).color);
    }

    public static void main(String[] args) {
        Car a1 = new Car("green");
        Car a2 = new Car("red");

        //hashMap stores Car type and its quantity
        HashMap<Car, Integer> m = new HashMap<Car, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Car("green")));
    }
}

녹색 자동차를 찾을 수 없습니다

2. hashCode ()로 인한 문제

재정의되지 않은 방법으로 인해 문제가 발생합니다 hashCode(). 와 사이의 계약은 다음 equals()hashCode()같습니다.

  1. 두 객체가 같으면 해시 코드가 동일해야합니다.
  2. 두 객체의 해시 코드가 동일하면 같을 수도 있고 같지 않을 수도 있습니다.

    public int hashCode(){  
      return this.color.hashCode(); 
    }

4

값 객체를 사용할 때 유용합니다 . 다음은 포틀랜드 패턴 리포지토리 에서 발췌 한 것입니다 .

값 객체의 예는 숫자, 날짜, 돈 및 문자열과 같은 것입니다. 일반적으로 그것들은 아주 널리 사용되는 작은 물체입니다. 그들의 정체성은 그들의 객체 정체성보다는 상태에 근거한다. 이런 방식으로 동일한 개념적 값 객체의 사본을 여러 개 가질 수 있습니다.

따라서 1998 년 1 월 16 일을 나타내는 개체의 복사본을 여러 개 가질 수 있습니다. 이러한 복사본은 서로 동일합니다. 이와 같은 작은 개체의 경우 날짜를 나타 내기 위해 단일 개체를 사용하지 않고 새 개체를 만들어 이동하는 것이 더 쉽습니다.

값 객체는 항상 Java에서 .equals ()를 재정의해야합니다 (또는 Smalltalk에서 =). .hashCode ()를 재정의해야합니다.


3

다른 두 개의 (B) (C)를 집계하는 클래스 (A)가 있고 해시 테이블 내에 (A)의 인스턴스를 저장해야한다고 가정하십시오. 기본 구현은 인스턴스 구별 만 허용하지만 (B)와 (C)에 의한 것은 아닙니다. 따라서 A의 두 인스턴스는 같을 수 있지만 기본적으로 올바른 방식으로 비교할 수는 없습니다.


3

equals와 hashcode 메소드는 객체 클래스에 정의되어 있습니다. 기본적으로 equals 메소드가 true를 리턴하면 시스템은 더 나아가 해시 코드의 값을 점검합니다. 두 객체의 해시 코드도 동일하면 객체는 동일한 것으로 간주됩니다. 따라서 equals 메서드 만 재정의하는 경우 재정의 된 equals 메서드가 2 개의 개체가 같음을 나타내더라도 시스템 정의 해시 코드는 2 개의 개체가 같음을 나타내지 않을 수 있습니다. 따라서 해시 코드도 무시해야합니다.


equals 메서드가 true를 반환하면 해시 코드를 확인할 필요가 없습니다. 그러나 두 객체에 서로 다른 해시 코드가있는 경우 equals를 호출 할 필요없이 서로 다른 것으로 간주 할 수 있어야합니다. 또한, 목록에있는 어떤 것도 특정 해시 코드를 가지고 있지 않다는 것을 아는 것은 목록에있는 어떤 것도 해당 해시 코드와 일치하는 객체가 없다는 것을 의미합니다. 간단한 예로, 해시 코드가 짝수 인 객체 목록과 홀수 인 객체 목록이있는 경우 해시 코드가 짝수 인 객체는 두 번째 목록에 없습니다.
supercat

"동일한"메소드가 일치한다고 표시 한 두 개의 오브젝트 X와 Y가 있지만 X의 해시 코드가 짝수이고 Y의 해시 코드가 홀수 인 경우, 오브젝트 Y의 해시 코드가 홀수이고 저장되었다는 위에서 설명한 콜렉션 두 번째 목록에서 객체 X와 일치하는 항목을 찾을 수 없습니다. X의 해시 코드가 짝수이고 두 번째 목록에 짝수 번호의 해시 코드가있는 객체가 없으므로 귀찮게하지 않습니다. Y가 X와 일치하더라도 X와 일치하는 것을 검색합니다.
supercat

... 많은 컬렉션이 해시 코드가 같지 않다는 것을 암시하는 것을 비교하지 않아도 될 것입니다. 해시 코드를 알 수없는 두 개의 객체가 주어지면 해시 코드를 계산하는 것보다 직접 비교하는 것이 더 빠르기 때문에 해시 코드가 동일하지 않은 것으로보고하지만 반환 true되는 항목 equals이 일치하는 것으로 간주되지는 않습니다. 다른 한편으로, 컬렉션이 동일한 해시 코드를 가질 수 없다는 것을 알게되면, 그것들이 동등하다는 것을 알지 못할 것입니다.
supercat

3

Java의 동일 및 해시 코드 메소드

그것들은 모든 클래스의 슈퍼 클래스 인 java.lang.Object 클래스의 메소드입니다 (사용자 정의 클래스 및 Java API에 정의 된 클래스).

이행:

공개 부울 같음 (오브젝트 obj)

공개 int hashCode ()

여기에 이미지 설명을 입력하십시오

공개 부울 같음 (오브젝트 obj)

이 방법은 단순히 두 객체 참조 x와 y가 동일한 객체를 참조하는지 확인합니다. 즉, x == y인지 확인합니다.

이 반사적이다 : 임의의 참조 값 x에 대해, x.equals (X)가 true를 반환한다.

대칭입니다. 모든 참조 값 x 및 y에 대해, y.equals (x)가 true를 반환하는 경우에만 x.equals (y)가 true를 반환해야합니다.

전 이적입니다. 모든 참조 값 x, y 및 z에 대해 x.equals (y)가 true를 반환하고 y.equals (z)가 true를 반환하면 x.equals (z)는 true를 반환해야합니다.

일관된 결과 : 모든 참조 값 x 및 y에 대해 x.equals (y)를 여러 번 호출하면 객체의 동등 비교에 사용 된 정보가 수정되지 않은 경우 지속적으로 true를 반환하거나 false를 반환합니다.

null이 아닌 참조 값 x의 경우 x.equals (null)은 false를 반환해야합니다.

공개 int hashCode ()

이 메소드는이 메소드가 호출 된 오브젝트의 해시 코드 값을 리턴합니다. 이 메소드는 해시 코드 값을 정수로 리턴하며 Hashtable, HashMap, HashSet 등과 같은 해시 기반 콜렉션 클래스의 이점을 위해 지원됩니다.이 메소드는 equals 메소드를 대체하는 모든 클래스에서 대체되어야합니다.

hashCode의 일반적인 계약은 다음과 같습니다.

Java 응용 프로그램을 실행하는 동안 동일한 객체에서 두 번 이상 호출 될 때마다 hashCode 메소드는 객체의 동등 비교에 사용 된 정보가 수정되지 않는 한 동일한 정수를 일관되게 반환해야합니다.

이 정수는 응용 프로그램의 한 실행에서 동일한 응용 프로그램의 다른 실행까지 일관성을 유지하지 않아도됩니다.

equals (Object) 메소드에 따라 두 오브젝트가 동일한 경우 두 오브젝트 각각에서 hashCode 메소드를 호출하면 동일한 정수 결과가 생성되어야합니다.

equals (java.lang.Object) 메소드에 따라 두 오브젝트가 동일하지 않은 경우 두 오브젝트 각각에서 hashCode 메소드를 호출하면 고유 한 정수 결과가 생성되어야합니다. 그러나 프로그래머는 동일하지 않은 객체에 대해 고유 한 정수 결과를 생성하면 해시 테이블의 성능을 향상시킬 수 있음을 알고 있어야합니다.

동일한 객체는 동일한 해시 코드를 생성해야하지만 동일하지 않은 객체는 고유 한 해시 코드를 생성 할 필요는 없습니다.

자원:

자바 레인지

그림


사진 (비디오 링크)이 개인 모드입니다. 볼 수 있도록 공개하십시오.
UdayKiran Pulipati

2

아래 예제에서 Person 클래스에서 equals 또는 hashcode에 대한 재정의를 주석 처리하면이 코드는 Tom의 순서를 찾지 못합니다. 해시 코드의 기본 구현을 사용하면 해시 테이블 조회에 실패 할 수 있습니다.

내가 가지고있는 것은 사람별로 사람들의 순서를 끌어내는 단순화 된 코드입니다. 해시 테이블에서 사람이 키로 사용되고 있습니다.

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

    public Person(String name, int age, String socialSecurityNumber) {
        this.name = name;
        this.age = age;
        this.socialSecurityNumber = socialSecurityNumber;
    }

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}

2

문자열 클래스 및 랩퍼 클래스는 Object 클래스 equals()와 다른 구현 및 hashCode()메소드를 갖습니다 . Object 클래스의 equals () 메소드는 내용이 아닌 객체의 참조를 비교합니다. Object 클래스의 hashCode () 메서드는 내용이 같은지 여부에 관계없이 모든 단일 객체에 대해 고유 한 해시 코드를 반환합니다.

맵 콜렉션을 사용할 때 문제가 발생하고 키가 영구 유형, StringBuffer / 빌더 유형입니다. String 클래스와 달리 equals () 및 hashCode ()를 재정의하지 않기 때문에 equals ()는 내용이 같더라도 두 개의 다른 객체를 비교할 때 false를 반환합니다. hashMap이 동일한 콘텐츠 키를 저장하게합니다. 동일한 콘텐츠 키를 저장한다는 것은 Map이 중복 키를 전혀 허용하지 않기 때문에 Map 규칙을 위반한다는 의미입니다. 따라서 클래스의 hashCode () 메소드뿐만 아니라 equals () 메소드를 대체하고 구현 (IDE는 이러한 메소드를 생성 할 수 있음)을 제공하여 String의 equals () 및 hashCode ()와 동일하게 작동하고 동일한 컨텐츠 키를 방지합니다.

equals ()가 해시 코드에 따라 작동하므로 equals ()와 함께 hashCode () 메서드를 재정의해야합니다.

또한 equals ()와 함께 hashCode () 메서드를 재정의하면 equals ()-hashCode () 계약을 그대로 유지하는 데 도움이됩니다. "두 객체가 같으면 해시 코드가 같아야합니다."

hashCode ()에 대한 사용자 정의 구현을 언제 작성해야합니까?

우리가 알고 있듯이 HashMap의 내부 작업은 해싱 원칙에 있습니다. 엔트리 세트가 저장되는 특정 버킷이 있습니다. 동일한 범주 객체를 동일한 인덱스에 저장할 수 있도록 요구 사항에 따라 hashCode () 구현을 사용자 정의합니다. put(k,v)메소드를 사용하여 값을 맵 콜렉션에 저장하는 경우 put ()의 내부 구현은 다음과 같습니다.

put(k, v){
hash(k);
index=hash & (n-1);
}

즉, 인덱스를 생성하고 인덱스는 특정 키 객체의 해시 코드를 기반으로 생성됩니다. 따라서 동일한 해시 코드 항목 세트가 동일한 버킷 또는 인덱스에 저장되므로이 방법으로 요구 사항에 따라 해시 코드를 생성하십시오.

그게 다야!


1

hashCode()메소드는 주어진 객체에 대해 고유 한 정수를 얻는 데 사용됩니다. 이 정수는이 개체가 일부에 저장 될 필요가있을 때, 버킷 위치를 결정하기 위해 사용되는 HashTable, HashMap데이터 구조 등을 포함한다. 기본적으로 Object의 hashCode()메소드는 객체가 저장된 메모리 주소의 정수 표현을 반환합니다.

hashCode()객체의 방법은 우리가에 삽입 할 때 사용되는 HashTable, HashMap또는 HashSet. HashTablesWikipedia.org에 대한 자세한 내용 은 참조하십시오.

지도 데이터 구조에 항목을 삽입하려면 키와 값이 모두 필요합니다. 키와 값이 모두 사용자 정의 데이터 유형 인 경우 키의 값은 hashCode()오브젝트를 내부적으로 저장할 위치를 결정합니다. 지도에서 객체를 조회해야하는 경우 키의 해시 코드에 따라 객체를 검색 할 위치가 결정됩니다.

해시 코드는 내부적으로 특정 "영역"(또는 목록, 버킷 등) 만 가리 킵니다. 다른 키 객체는 잠재적으로 동일한 해시 코드를 가질 수 있기 때문에 해시 코드 자체가 올바른 키를 찾도록 보장하지는 않습니다. 그런 HashTable다음이 영역 (해시 코드가 동일한 모든 키)을 반복하고 키의 equals()방법을 사용 하여 올바른 키를 찾습니다. 올바른 키를 찾으면 해당 키에 저장된 객체가 반환됩니다.

보시다시피, hashCode()equals()메소드를 조합 하여 객체를 저장하거나 조회 할 때 사용됩니다 HashTable.

노트:

  1. 항상 동일한 속성을 사용하여 생성 hashCode()하고 equals()둘 다 생성하십시오 . 우리의 경우와 마찬가지로 직원 ID를 사용했습니다.

  2. equals() 일관성이 있어야합니다 (객체가 수정되지 않은 경우 계속 같은 값을 반환해야 함).

  3. 때마다 a.equals(b), 다음 a.hashCode()과 같은 동일해야합니다 b.hashCode().

  4. 하나를 재정의하면 다른 것을 재정의해야합니다.

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html


hashCode()모든 객체에 대해 고유 한 정수를 반환하는 데 사용되는 것은 아닙니다. 불가능합니다. 네 번째 단락의 두 번째 문장에서이 내용을 모순했습니다.
Lorne의 후작

@EJP, 대부분의 경우 hascode ()는 두 개의 다른 객체에 대해 고유 한 interger를 반환합니다. 그러나 두 개의 서로 다른 객체에 대해 충돌 코드가있을 가능성이 있으며이 개념을 해시 코드 충돌 이라고 합니다. 참조하십시오 : tech.queryhome.com/96931/…
Paramesh Korrakuti

1

IMHO, 그것은 규칙에 따라-두 객체가 동일하면 동일한 해시를 가져야합니다. 즉, 동일한 객체는 동일한 해시 값을 생성해야합니다.

위에서 주어진 Object의 기본 equals ()는 ==로, 주소를 비교하고, hashCode ()는 주소를 정수로 반환합니다 (실제 주소에서 hash).

해시 기반 컬렉션에서 사용자 정의 객체를 사용해야하는 경우 equals () 및 hashCode ()를 모두 재정의해야합니다. 두 개의 다른 직원 객체를 재정의 할 수 있습니다. 이는 연령을 hashCode ()로 사용할 때 발생하지만 직원 ID가 될 수있는 고유 한 값을 사용해야합니다.


1

중복 객체를 확인하려면 사용자 정의 equals와 hashCode가 필요합니다.

해시 코드는 항상 숫자를 반환하기 때문에 알파벳 키 대신 숫자를 사용하여 객체를 검색하는 것이 항상 빠릅니다. 어떻게됩니까? 다른 객체에서 이미 사용 가능한 값을 전달하여 새 객체를 만들었다 고 가정합니다. 이제 전달 된 값이 같기 때문에 새 객체는 다른 객체와 동일한 해시 값을 반환합니다. 동일한 해시 값이 반환되면 JVM은 매번 동일한 메모리 주소로 이동하며 동일한 해시 값에 대해 둘 이상의 객체가있는 경우 equals () 메서드를 사용하여 올바른 객체를 식별합니다.


1

Map에서 사용자 정의 객체를 키로 저장하고 검색하려면 항상 사용자 정의 Object에서 equals 및 hashCode를 재정의해야합니다. 예 :

Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");

여기서 p1 & p2는 하나의 객체로 간주되며 map크기는 동일하므로 크기는 1입니다.


1
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

테스트 클래스

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

객체 클래스에서 equals (Object obj)는 주소 비교를 비교하는 데 사용되므로 테스트 클래스에서 두 객체를 비교하는 경우 메소드는 false를주는 것과 같지만 hashcode ()를 재정의하면 내용을 비교하고 적절한 결과를 얻을 수 있습니다.


아래 프로그램에 추가 한 테스트 클래스입니다.
Manash Ranjan Dakua

객체 클래스에서 equals (Object obj)는 주소 비교를 비교하는 데 사용되므로 테스트 클래스에서 두 객체를 비교하는 경우 메소드는 false를주는 것과 같지만 hashcode ()를 재정의하면 내용을 비교하고 적절한 결과를 얻을 수 있습니다.
Manash Ranjan Dakua

1
이 답변 바로 아래의 편집 링크를 사용하여 답변에 추가 할 수 있습니다 .. 답변을 불완전한 답변 2 개로 추가하지 마십시오
Suraj Rao

1

오버라이드 equals()하지 않으면 hashcode(), 당신 또는 다른 사람이 같은 클래스 타입을 해시 콜렉션에서 사용하지 않으면 문제가 발생하지 않을 것이다 HashSet. 저의 사람들은 문서화 된 이론을 여러 번 명확하게 설명했습니다. 저는 아주 간단한 예를 제시하려고 여기 있습니다.

equals()커스터마이징 된 것을 의미 해야하는 클래스를 생각해보십시오 .

    public class Rishav {

        private String rshv;

        public Rishav(String rshv) {
            this.rshv = rshv;
        }

        /**
        * @return the rshv
        */
        public String getRshv() {
            return rshv;
        }

        /**
        * @param rshv the rshv to set
        */
        public void setRshv(String rshv) {
            this.rshv = rshv;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Rishav) {
                obj = (Rishav) obj;
                if (this.rshv.equals(((Rishav) obj).getRshv())) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        @Override
        public int hashCode() {
            return rshv.hashCode();
        }

    }

이제이 주요 클래스를 고려하십시오 :-

    import java.util.HashSet;
    import java.util.Set;

    public class TestRishav {

        public static void main(String[] args) {
            Rishav rA = new Rishav("rishav");
            Rishav rB = new Rishav("rishav");
            System.out.println(rA.equals(rB));
            System.out.println("-----------------------------------");

            Set<Rishav> hashed = new HashSet<>();
            hashed.add(rA);
            System.out.println(hashed.contains(rB));
            System.out.println("-----------------------------------");

            hashed.add(rB);
            System.out.println(hashed.size());
        }

    }

다음과 같은 결과가 나옵니다.

    true
    -----------------------------------
    true
    -----------------------------------
    1

결과에 만족합니다. 그러나 재정의 하지 않으면 동일한 멤버 콘텐츠 hashCode()Rishav가진 객체 가 더 이상 고유 한 것으로 취급되지 않기 때문에 악몽을 일으킬 수 있습니다. hashCode기본 동작으로 생성되면 다음과 같이 출력됩니다.

    true
    -----------------------------------
    false
    -----------------------------------
    2

0

두 메소드 모두 Object 클래스에 정의되어 있습니다. 그리고 둘 다 가장 간단한 구현입니다. 따라서이 메소드에 구현을 더 추가해야 할 때 클래스에서 재정의합니다.

예를 들어, 객체의 equals () 메소드는 참조에 대한 동등성을 검사합니다. 따라서 상태를 비교 해야하는 경우 String 클래스에서와 같이 상태를 무시할 수 있습니다.


-3

Bah- "equals ()를 재정의하는 모든 클래스에서 hashCode ()를 재정의해야합니다."

[조슈아 블로흐의 효과적인 자바에서?]

이것이 잘못된 방법이 아닙니까? hashCode를 재정의하면 아마도 해시 키 클래스를 작성하고 있음을 암시하지만 동등을 재정의하는 것은 확실하지 않습니다. 해시 키로 사용되지 않는 클래스가 많이 있지만 다른 이유로 논리적 평등 테스트 방법을 원합니다. "같음"을 선택하면이 규칙을 과도하게 적용하여 hashCode 구현을 작성해야 할 수 있습니다. 달성 할 수있는 모든 것은 코드베이스에 테스트되지 않은 코드를 추가하는 것입니다. 또한 필요하지 않은 코드를 작성하는 것은 민첩하지 않습니다. 그것은 단지 잘못입니다 (그리고 ide 생성 된 것은 아마도 당신의 수공예품과 호환되지 않을 것입니다).

분명히 그들은 키로 사용되도록 작성된 객체에 대한 인터페이스를 위임해야합니까? 어쨌든 Object는 기본 hashCode () 및 equals () imho를 제공하지 않아야합니다. 아마도 많은 깨진 해시 컬렉션을 장려했을 것입니다.

어쨌든, 나는 "규칙"이 앞뒤로 쓰여졌다 고 생각합니다. 그 동안 평등 테스트 방법에 "같음"을 사용하지 않는 것이 좋습니다 :-(

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.