自定义Map的Key类型
在使用Map集合的时候可以发现对于Key与Value的类型实际上都可以由使用者任意决定,那么也就意味着依然可以使用自定义的类进行Key的设置。
范例:自定义Key
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map <Person,String> hashMap = new HashMap<Person,String>();
hashMap.put(new Person("张三",21),"牛逼!"); //使用自定义类作为了Key
hashMap.put(new Person("李四",18),"威武!");
System.out.println(hashMap.get(new Person("张三",21))); //通过Key找到Value
}
}
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
null
此时结果为null,接下来分析一下源码寻找原因:
//HashMap中put方法,在数据保存的时候发现会自动传入key的数据生成一个hash码,存储的时候是有一个hash数值的
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//HashMap中get方法,根据Key获取数据的时候依然要将传入的Key通过hash()的方法来获取其对应的hash码,那么也就证明查询的过程之中首先利用hashCode()来进行数据查询。
public V get(Object key) {
Node<K,V> e;
return (e = getNode(key)) == null ? null : e.value;
}
//get中用到的getNode方法,当使用getNode查询的时候还需要使用到equals()方法(如果hash码相同,再通过equals()方法进行比较里面的内容是否相同,从而确定两个key是否一致)
final Node<K,V> getNode(Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n, hash; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & (hash = hash(key))]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
对源码分析后得出结论:在自定义的Key类型所在的类种一定要覆写hashCode()与equals()方法,否则无法查找到。
范例:覆写hashCode()与equals()方法后再次查询
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map <Person,String> hashMap = new HashMap<Person,String>();
hashMap.put(new Person("张三",21),"牛逼!"); //使用自定义类作为了Key
hashMap.put(new Person("李四",18),"威武!");
System.out.println(hashMap.get(new Person("张三",21))); //通过Key找到Value
}
}
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
牛逼!
此时结果就出来了。
虽然允许使用自定义的类作为Key的类型,在实际的开发之中,对于Map集合的Key常用的类型有:
- String
- Long
- Integer
尽量使用系统类。
面试题:如果在进行HashMap进行数据操作的时候出现了Hash冲突(Hash码相同),HashMap是如何解决的?
当出现了Hash冲突之后为了保证程序的正常执行,会在冲突的位置上将所有Hash冲突的内容转为链表保存。