Java学习笔记(十九):HashMap和Hashtable
Map集合
用来操作“键 ---- 值”对应的数据,可以使用Map<K,V>接口。Map集合有以下几个常用实现类:HashMap,HashTable,LinkedHashMap,TreeMap等,将在下面一一介绍。
Map集合有以下特点:
- 一个映射不能包含重复的键;
- 一个 “键(K)” 只能映射到一个 “值(V)”,即每个键最多只能映射到一个值。
Map接口和Collection接口的不同点:
- Map是双列的,Collection是单列的;
- Map的键唯一,Collection的子体系Set是唯一的;
- Map集合的数据结构针对键有效,跟值无关;Collection集合的数据结构是针对元素有效。
HashMap
特有方法:
- 添加功能:
V put(K key,V value):添加元素。
这个其实还有另一个功能:替换
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
- 删除功能:
void clear():移除所有的键值对元素
V remove(Object key):根据键删除键值对元素,并把值返回
- 判断功能:
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
- 获取功能:
Set<Map.Entry<K,V>> entrySet(): 返回一个键值对的Set集合
V get(Object key):根据键获取值
Set<K> keySet():获取集合中所有键的集合
Collection<V> values():获取集合中所有值的集合
- 长度功能:
int size():返回集合中的键值对的对数
- 遍历集合:
1.键找值(keySet方法):
首先获取所有键的集合,遍历键的集合。获取到每一个键,根据键找值。
Set<Integer> integers = hm.keySet(); //获取所有的键集
System.out.println(integers);
//遍历键集
for (Integer key : integers) {
//键找值
String value = hm.get(key);
System.out.println(key+"==="+value);
}
2.把所有的键值对对象全部获取出来(entrySet方法):
首先获取所有键值对对象的集合,遍历键值对对象的集合,获取到每一个键值对对象,再根据键值对对象找键和值。
Set<Map.Entry<Integer, String>> entries = hm.entrySet();
//遍历键值对集合
for (Map.Entry<Integer, String> node : entries) {
//分别获取键和值
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key+"==="+value);
}
3.JDK1.8之后的forEach方法
HashMap<Integer, String> hm = new HashMap<>();
hm.put(100, "aaa");
hm.put(200, "bbb");
hm.put(300, "ccc");
hm.put(400, "ddd");
//JDK1.8 提供的遍历方式forEach()方法
hm.forEach(new BiConsumer<Integer, String>() {
@Override
public void accept(Integer key, String value) {
System.out.println(key+"==="+value);
}
});
注意:
Map集合的数据结构针对键有效,跟值无关。需要注意键是自定义类的情况。对于作为键值的自定义类,需要重写hashCode和equals方法。具体情况如下:
HashMap<Student, String> hm = new HashMap<>();
hm.put(new Student("张三", 23),"s001");
hm.put(new Student("张三", 23), "s002");
hm.put(new Student("李四", 24), "s003");
hm.put(new Student("王五", 25), "s004");
因为每个Student类对象的地址值不一样,所以要区分两个张三,就需要重写Student类的hashCode和equals方法。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
HashMap和HashTable区别:
- HashMap: 线程不安全,效率高。允许null值和null键;
- Hashtable: 线程安全 ,效率低。不允许null值和null键。
LinkedHashMap
- 底层的数据结构是链表和哈希表 元素有序 并且唯一;
- 元素的有序性由链表数据结构保证 唯一性由 哈希表数据结构保证;
- Map集合的数据结构只和键有关。
TreeMap
- 键的数据结构是红黑树,可保证键的排序和唯一性;
- 排序分为自然排序和比较器排序 ;
- 线程是不安全的效率比较高。
当使用自然排序(空参构造),要求键实现Comparable接口,重写compareTo 方法,根据方法返回值的正负零来判断键排列的顺序。
当使用比较器排序(空参构造),要求键实现Comparable接口,重写compareTo 方法,根据方法返回值的正负零来判断键排列的顺序。
工具类Collections
针对集合操作的工具类。
常用方法:
public static <T> void sort(List<T> list):排序,默认按照自然顺序
public static <T> int binarySearch(List<?> list,T key):二分查找
public static <T> T max(Collection<?> coll):获取最大值
public static void reverse(List<?> list):反转
public static void shuffle(List<?> list):随机置换