其实这个问题是答案就是用自定义类作为key,必须重写equals()和hashCode()方法。
以下是Object对象API关于equal方法和hashCode方法的说明:
- 相等(相同)的对象必须具有相等的哈希码(或者散列码)
- 两个对象的hashCode相同,它们并不一定相同
举例说明:
相等(相同)的对象必须具有相等的哈希码(或者散列码)
想象一下,假如两个Java对象A和B,A和B相等(eqauls结果为true),但A和B的哈希码不同,则A和B存入HashMap时的哈希码计算得到的HashMap内部数组位置索引可能不同,那么A和B很有可能允许同时存入HashMap,显然相等/相同的元素是不允许同时存入HashMap,HashMap不允许存放重复元素。
两个对象的hashCode相同,它们并不一定相同
也就是说,不同对象的hashCode可能相同;假如两个Java对象A和B,A和B不相等(eqauls结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同这时HashMap会在该位置建立一个链接表,将A和B串起来放在该位置,显然,该情况不违反HashMap的使用原则,是允许的。当然,哈希冲突越少越好,尽量采用好的哈希算法以避免哈希冲突。
Hashset是继承Set接口,Set接口又实现Collection接口,这是层次关系。那么Hashset、Hashmap、Hashtable中的存储操作是根据什么原理来存取对象的呢?
下面以HashSet为例进行分析,我们都知道:在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?在java的集合中,判断两个对象是否相等的规则是:
-
判断两个对象的hashCode是否相等, 如果不相等,认为两个对象也不相等,完毕。如果相等,转入2(
这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。
) -
判断两个对象用equals运算是否相等,如果不相等,认为两个对象也不相等;如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
为什么是两条准则,难道用第一条不行吗?不行,因为前面已经说了,hashcode()相等时,equals()方法也可能不等,所以必须用第2条准则进行限制,才能保证加入的为非重复元素。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class Person {
String id;
String name;
public Person(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return "id = " + id + " , name = " + name;
}
}
class Student {
String id;
String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public int hashCode() {
return id.hashCode();
}
public boolean equals(Object ob) {
Student student = (Student)ob;
if(student.id.equals(this.id)) {
return true;
}else {
return false;
}
}
public String toString() {
return "id = " + id + " , name = " + name;
}
}
public class HashCodeTest {
public static void main(String[] args) {
testStringHash();
testHashSetWithoutEquals();
testHashSetWithEquals();
}
//测试没有实现equals和hashCode
public static void testHashSetWithoutEquals() {
Set<Person> personSet = new HashSet<Person>();
personSet.add(new Person("123", "Tom"));
personSet.add(new Person("123", "Tom"));
Iterator<Person> iterator = personSet.iterator();
while(iterator.hasNext()) {
Person person = iterator.next();
System.out.println(person.toString());
}
}
//测试实现了equals和hashCode
public static void testHashSetWithEquals() {
Set<Student> studentSet = new HashSet<Student>();
studentSet.add(new Student("123", "Tom"));
studentSet.add(new Student("123", "Tom"));
Iterator<Student> iterator = studentSet.iterator();
System.out.println("********************");
while(iterator.hasNext()) {
Student student = iterator.next();
System.out.println(student.toString());
}
}
//String类覆盖了equals和hashCode参考jdk实现
public static void testStringHash() {
Object a = new Object();
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println("hashCode s1 = " + s1.hashCode());
System.out.println("hashCode s2 = " + s2.hashCode());
Set hashSet = new HashSet<String>();
hashSet.add(s1);
hashSet.add(s2);
Iterator it = hashSet.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println("*******************");
}
}
同理hashMap的测试如下
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
class Person {
String id;
String name;
public Person(String id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return "id = " + id + " , name = " + name;
}
}
class Student {
String id;
String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
public int hashCode() {
return id.hashCode();
}
public boolean equals(Object ob) {
Student student = (Student)ob;
if(student.id.equals(this.id)) {
return true;
}else {
return false;
}
}
public String toString() {
return "id = " + id + " , name = " + name;
}
}
public class HashMapTest {
public static void main(String[] args) {
testHashMapWithoutEquals();
testHashMapWithEquals();
}
public static void testHashMapWithoutEquals() {
Map<Person, String> hMap = new HashMap<Person, String>();
Person person1 = new Person("123", "Tom");
Person person2 = new Person("123", "Tom");
hMap.put(person1, "address");
hMap.put(person2, "address");
Iterator iterator = hMap.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
Person key = (Person) entry.getKey();
String val = (String) entry.getValue();
System.out.println("key = " + key + " value = " + val);
}
}
public static void testHashMapWithEquals() {
System.out.println("*********************");
Map<Student, String> hMap = new HashMap<Student, String>();
Student student1 = new Student("123", "Tom");
Student student2 = new Student("123", "Tom");
hMap.put(student1, "address");
hMap.put(student2, "address");
Iterator iterator = hMap.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
Student key = (Student) entry.getKey();
String val = (String) entry.getValue();
System.out.println("key = " + key + " value = " + val);
}
}
}
相关文章