equals 방법과hashcode 방법

16875 단어 HashCode
왜 equals와hashcode 방법을 사용해야 하는가 equals: 때때로 우리는 두 대상이 같은지(수동으로 호출)hashcode를 비교해야 한다. 왜냐하면 우리는 유일한 대상을 집합에 저장해야 하기 때문이다(또는 실제 집합에 중복된 값이 존재할 수 없으며, 중복된 것이 존재하는지도 비교해야 한다. 예를 들어hashset,hashmap의 키)(프로그램 자체 호출)
Object의 equals는 두 대상의 메모리 주소를 비교하고hashcode 방법은 해시 코드 값으로 메모리 주소와 관련이 있고 int 값이다. 그러나hashcode 방법의 알고리즘은 대상 자체와 관련이 있다(jdk는 대상의 주소나 문자열이나 숫자에 따라 계산된다). 그래서 equals를 다시 쓸 때 대상 자체에 변화가 발생한다.물론 hashcode도 달라졌습니다. (Object 클래스에서 정의한hashCode 방법은 서로 다른 대상에 대해 서로 다른 정수를 되돌려줍니다)
A
다시 쓰기 전:
package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        Map<Student,String> m = new HashMap<Student,String>();
        
        m.put(new Student(1,"zhangsan"), "aa");
        m.put(new Student(1,"zhangsan"), "bb");
        m.put(new Student(2," "), "cc");
        
        System.out.println(new Student(1,"zhangsan") == new Student(1,"zhangsan"));
        System.out.println(new Student(1,"zhangsan").equals(new Student(1,"zhangsan")));
        Iterator<Entry<Student, String>> itmap = m.entrySet().iterator();
        while (itmap.hasNext()) {
            System.out.println(itmap.next());
            System.out.println(m.get(new Student(1,"zhangsan")));
        }
        
        System.out.println();
        HashSet<Student> hs = new HashSet<Student>();
        hs.add(new Student(1,"zhangsan"));
        hs.add(new Student(1,"zhangsan"));
        hs.add(new Student(2," "));
        Iterator<Student> itset = hs.iterator();
        while (itset.hasNext()) {
            System.out.println(itset.next());
             System.out.println(m.get(new Student(1, "zhangsan")));
        }

        /*
         * for(Iterator it = m.entrySet().iterator(); it.hasNext();){
         * System.out.println(m.get(new Student(1, "zhangsan"))); }
         */
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

}

결과:
false
false
1+zhangsan+33263331;=bb
:-------null
1+zhangsan+12677476;=aa
:-------null
2+ +6413875;=cc
:-------null

1+zhangsan+28737396;
null
1+zhangsan+27744459;
null
2+ +6927154;
null



B
equals만 다시 쓰기
package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        // 
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

    public boolean equals(Object obj) {
        if (null == obj) {
            return false;
        } else {
            if (obj instanceof Student) {
                Student o = (Student) obj;
                if (this.name == o.name && this.num == o.num) {
                    return true;
                }
            }
            return false;
        }
    }

}

결과:
false
true
1+zhangsan+33263331;=bb
:-------null
1+zhangsan+12677476;=aa
:-------null
2+ +6413875;=cc
:-------null

1+zhangsan+28737396;
null
1+zhangsan+27744459;
null
2+ +6927154;
null



표면상 new Student(1,"zhangsan").equals(new Student(1, "zhangsan")는true이지만 두'동일'대상은 모두hashmap의 키 값으로hashset에 저장되어 있습니다. 왜요?jdk는 당신처럼 간단한 equals가 아니기 때문에 두 대상을 비교할 때 대상의hash코드 값을 비교합니다. 하shcode()를 다시 쓸 때만hashcode가 일치할 때 상등합니다. 이로 인해hashset에 중복된 데이터가 있고hashmap에 같은 키가 있습니다. 이 같은 키를 사용하여value를 꺼낼 때 프로그램이 어떤 키를 호출했는지 몰라서value를 찾을 수 없습니다.쓰레기hashset과hashmap이 나왔어요.
C
hashcode만 다시 쓰기
package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        // 
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

    public int hashCode() {
        return num * name.hashCode();
    }

}

결과:
false
false
1+zhangsan+-1432604556;=bb
:-------null
1+zhangsan+-1432604556;=aa
:-------null
2+ +1362968;=cc
:-------null

1+zhangsan+-1432604556;
null
1+zhangsan+-1432604556;
null
2+ +1362968;
null



4
모두 다시 쓰기:
package collectionsFramework;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashSetTest {
    public static void main(String[] args) {
        // 
    }
}

class Student {
    int num;
    String name;

    Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + "+" + name + "+" + this.hashCode() + ";";
    }

    public boolean equals(Object obj) {
        if (null == obj) {
            return false;
        } else {
            if (obj instanceof Student) {
                Student o = (Student) obj;
                if (this.name == o.name && this.num == o.num) {
                    return true;
                }
            }
            return false;
        }
    }

    public int hashCode() {
        return num * name.hashCode();
    }

}

결과:
false
true
1+zhangsan+-1432604556;=bb
 :-------bb
2+ +1362968;=cc
 :-------bb

1+zhangsan+-1432604556;
bb
2+ +1362968;
bb

 
두 번째 코드의 운행 결과를 보면 equals를 다시 쓰기만 하면 된다는 것을 알 수 있다.
그러나 new Student(1, "zhangsan")은 모두 Hashset(대상이 같지 않고 hashcode 값이 다르다는 뜻)에 저장되고,hashmap에서 m.get(new Student(1, "zhangsan"))은null,
new Student(1, "zhangsan")은 두 개의 값에 대응한다. "aa", "bb", 모순되어 키값으로 사용할 수 없다.
그래서 이때hashcode를 동시에 다시 써야 합니다. 그 다음에hashset 뒤에 같은 것을 추가하면 이전에 추가한 것을 덮어씁니다. 그러면 하나만 추가됩니다.hashmap에는 두 대상이 같고 그 다음에 키 값으로 추가됩니다.
 

좋은 웹페이지 즐겨찾기