一、Map接口概述
Map接口是由一系列键值对组成的集合,提供了key到value之间的映射,并且不能存在相同的key值,value值可以相同。
Map接口继承关系:
Map接口提供对一个值的集合与一个键的规则集进行查询、更新和读取等方法:
方法 | 描述 |
public V put(K key, V value); | 向Map中添加数据 |
public V get(Object key); | 根据key取得对应的value,没有返回null |
public Set<K> keySet(); | 取得所有key信息 |
public Collection<V> values(); | 取得所有value信息 |
public Set<Map.Entry<K, V>> entrySet(); | 将Map集合变为Set集合 |
Map本身是一个接口,要使用Map需要通过子类进行对象实例化。Map接口的常用子类有如下四个: HashMap、Hashtable、TreeMap、ConcurrentHashMap。
二、HashMap子类
1.HashMap类实现原理
以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表结构。
2.HashMap基本操作
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"hello");
map.put(2,"word");
map.put(2,"word");//重复key值
System.out.println(map);
//根据key值取得value
System.out.println(map.get(1));
System.out.println(map.get(3));
}
}
输出结果:
{1=hello, 2=word}
hello
null
3.取得HashMap中所有key信息
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"hello");
map.put(2,"word");
map.put(2,"word");//重复key值
// 取得Map中所有的key信息,返回一个Set集合
Set<Integer> set=map.keySet();
//实例化Iterator,完成标准输出
Iterator<Integer> iterator=set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
4.HashMap源码分析
三、Hashtable子类
1.HashTable类概述
1)Hashtable 继承于Dictionary,实现了Map接口
2)Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。
2.HashMap与Hashtable的区别
区别 | HashMap | Hashtable |
推出版本 | JDK1.2 | JDK1.0 |
性能 | 异步处理,性能高 | 同步处理,性能低 |
安全性 | 非线程安全 | 线程安全 |
null操作 | 允许存放null(有且只有一个) | key和value都不为空 |
四、TreeMap子类
1.TreeMap类概述
1)TreeMap 是一个有序的key-value集合,基于红黑树(Red-Black tree)实现,每一个key-value节点作为红黑树的一个节点。2)TreeMap存储时会进行排序,会根据key来对key-value键值对进行排序,其中排序方式也是分为两种:一种是自然排序,一种是定制排序,具体取决于使用的构造方法。
自然排序:TreeMap中所有的key必须实现Comparable接口,并且所有的key都应该是同一个类的对象,否则会报ClassCastException异常。
定制排序:定义TreeMap时,创建一个comparator对象,该对象对所有的treeMap中所有的key值进行排序,采用定制排序的时候不需要TreeMap中所有的key必须实现Comparable接口。
注意:有Comparable出现的地方,判断数据就依靠compareTo()方法完成,不再需要equals()与hashCode()
五、Map集合使用Iterator输出
Map接口与Collection接口不同,Collection接口有iterator()方法可以很方便的取得Iterator对象来输出,而Map接口本身并没有此方法。
在Map接口里面有一个重要的方法,它可以将Map集合转为Set集合:
public Set<Map.Entry<K, V>> entrySet();
范例:通过Iterator输出Map集合
public class Test {
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"hello");
map.put(2,"word");
map.put(3,"java");
//1.将Map集合转换为Set集合
Set<Map.Entry<Integer,String>> set = map.entrySet() ;
// 2.获取Iterator对象
Iterator<Map.Entry<Integer,String>> iterator = set.iterator() ;
// 3.输出
while (iterator.hasNext()) {
// 4.取出每一个Map.Entry对象
Map.Entry<Integer,String> entry = iterator.next() ;
// 5.取得key和value
System.out.println(entry.getKey()+" = " +entry.getValue()) ;
}
}
}
六、Map中的key值
之前使用Map集合的时候使用的都是系统类作为key(Integer,String等)。实际上用户也可采用自定义类作为key。
这个时候一定要记得覆写Object类的hashCode()与equals()方法
范例:覆写hashCode()与equals()方法
class Person {
private Integer age ;
private String name ;
public Person(Integer age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(age, person.age) &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
Map<Person,String> map = new HashMap<>() ;
map.put(new Person(15,"张三"),"hello") ;
System.out.println(map.get(new Person(15,"张三")));
}
}
实际开发中,我们一般都是采用系统类(String,Integer等)作为Key值,这些系统类都帮助用户覆写好了hashCode()与equals()方法。