文章目录
Map接口
Map接口是区别去Collection接口的集合中的另一大类,对于Collection来说,它们使用的是单列存储,而Map都是双列存储。
实现类:
1、HashMap
2、TreeMap
3、HashTable
…
创建:Map map = new HashMap();
Map接口的特点
1、双列存储,即键值对(键—值)。
2、键不能重复、而值可以重复。
3、将键映射到值的对象。
4、一个映射不能包含重复的键。
5、每个键最多只能映射到一个值。
6、键去重复:使用hashCode方法求得的hash值。
7、如果有重复的键,后面键的值会把前面添加进去的键的值覆盖掉。
8、允许有一个空的键。
Map接口的常用方法
返回值 | 方法名 | 功能 |
---|---|---|
V | put(K key,V value) | 根据键和值向集合中添加元素 |
V | remove(Object key) | 通过键删除键值对 |
void | clear() | 清空Map集合 |
boolean | containsKey(Object key) | 判断有没有指定的键 |
boolean | containsValue(Object value) | 判断有没有指定的值 |
boolean | isEmpty() | 判断Map集合是否为空 |
int | size() | 判断有几组键值对 |
V | get(Object key) | 通过键获取值 |
Set<Map.EntrySet<K,V>> | entrySet() | 返回一个包含键值对的Set集合 |
Collection | values() | 返回一个只包含值的Collection集合 |
Set | keySet() | 返回一个只包含键的Set集合 |
代码示例
import java.util.HashMap;
import java.util.Map;
public class MapDemo {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
//添加元素
map.put(100,"stu1");
map.put(100,"stu1");
map.put(101,"stu2");
map.put(102,"stu3");
map.put(103,"stu4");
map.put(104,"stu5");
map.put(null,null);//可为空
System.out.println(map);//{null=null,100=stu1, 101=stu2, 102=stu3, 103=stu4, 104=stu5} 无重复
//通过键删除键值对--返回值
System.out.println(map.remove(104));//stu5
System.out.println(map);
//判断-键
System.out.println(map.containsKey(102));
//判断-值
System.out.println(map.containsValue("stu2"));
//判断为空
System.out.println(map.isEmpty());
//判断大小
System.out.println(map.size());
//通过键获取值
System.out.println(map.get(103));
//返回一个只包含值的Collection集合
System.out.println(map.values());
//keySet 返回一个只包含键的Set集合
System.out.println(map.keySet());
//entrySet 返回一个包含键值对的Set集合
System.out.println(map.entrySet());
}
}
实现类:HashMap
概述
事实上我们对于HashMap的认识早已经开始了,而不仅仅是在Map集合中认识的,在上一篇文章link中我们曾经讲到了一个Set接口的实现类----HashSet,而HashSet的底层实现就是HashMap,因此当我们学习HashMap的各种方法时,它和HashSet都是相同的。
HashMap的特点
1、Map接口的特点,HashMap都有。
2、键不可以重复,值可以重复。
3、底层使用哈希表。
4、线程不安全。
5、允许key为null,但只允许有一个null,value可以有多个null。
HashMap的存储结构
哈希表
说到HashMap的存储结构,我们就不得不说到HashMap的底层实现—哈希表。我们知道数据结构的物理存储方式有两种:顺序存储结构和链式存储结构。像栈、队列、树、图等都是从逻辑结构去抽象的,映射到内存中,也就是这两种物理存储结构。哈希表的主干就是数组,它可以像数组一样一次定位直达战场,比如我们要新增或查找某个元素,我们通过把当前元素的关键字通过某个函数映射到数组中的某个位置,通过数组下标一次就可以完成操作,而这个函数一般为哈希函数,即计算出当前元素关键字的hash值。
以查找元素为例:
HashMap
HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个键值(key-value)对。简单来说,Map就是保存两个对象之间的映射关系的一种集合。如图所示:
1、数据结构:数组+链表。
2、HashMap中有一个Entry类型的数组。
3、可以通过Entry<K,V>获得数组的节点,存储的元素是键值对。
4、哈希碰撞:当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入时发现该位置已经被其他元素占用了,这种情况就叫做哈希碰撞,也叫哈希冲突。我们知道数组是一块连续的固定长度的内存空间,而哈希函数是用来计算元素存在数组中的位置的,这就不可避免的会发生计算结果相同的情况,就会产生哈希碰撞,而HashMap解决哈希碰撞的方法就是链地址法,即数组+链表。
HashMap的常用方法
HashMap的方法和HashSet的方法有许多的相同之处,因为底层实现是一样的,又因为HashMap是Map的实现类,所以Map的方法在HashMap种基本都有实现,这里会简单列举一些HashMap的常用方法。
返回值类型 | 方法名 | 功能 |
---|---|---|
V | put ( K key,V value ) | 添加元素(键值对)到集合中,当有覆盖时会返回被覆盖的值 |
void | put ( Map m ) | 将指定Map集合中的元素添加到集合中 |
V | remove ( Object key ) | 通过键删除集合中的键值对 |
V | replace ( K key,V value ) | 用指定值替换指定位置的值,返回被替换的值 |
boolean | replace ( K key,V old,V new ) | 在指定位置用新的值替换旧的值 |
int | size ( ) | 求集合中的键值对个数 |
V | get(Object key) | 通过键获取值 |
Set<Map.EntrySet<K,V>> | entrySet() | 返回一个包含键值对的Set集合 |
Collection | values() | 返回一个只包含值的Collection集合 |
Set | keySet() | 返回一个只包含键的Set集合 |
代码示例
import java.util.HashMap;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Integer,Character> map = new HashMap<>();
//添加元素到集合末尾,有覆盖时返回被覆盖的Value
map.put(100,'地');
System.out.println(map.put(100,'天'));
map.put(101,'地');
map.put(102,'人');
HashMap<Integer,Character> map1 = new HashMap<>();
map1.put(10,'东');
map1.put(11,'西');
map1.put(12,'南');
map1.put(13,'北');
//将指定元素集合复制到此集合
map.putAll(map1);
System.out.println(map1);
System.out.println(map);
//通过键删除键值对---返回被删除的值
System.out.println(map.remove(102));
System.out.println(map);
//通过键修改值,返回被修改的值
System.out.println(map.replace(13,'下'));
System.out.println(map);
//replace(K key,V old,V new) 在key的位置上用新的value替换就的value
System.out.println(map.replace(12,'南','上'));
System.out.println(map);
//size() 求大小
System.out.println(map.size());
}
}
实现类:TreeSet
TreeSet的特点
1、TreeSet中的所有元素都保持着某一种固定的顺序(元素的自然顺序)。
2、适用于按自然顺序或自定义顺序遍历键(Key)。
3、键(Key)是有序的,值不做要求。
4、Key值所在类必须实现Comparable接口。
5、重写CompareTo方法。TreeMap根据CompareTo的逻辑,对key进行排序。
6、键是红黑树结构,可以保证键的排序和唯一性。
TreeSet的使用
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Integer,String> treeMap = new TreeMap<>();
treeMap.put(104,"Jim");
treeMap.put(104,"Jim");
treeMap.put(102,"Jim");
treeMap.put(106,"Jim2");
treeMap.put(101,"Jim1");
System.out.println(treeMap);//{101=Jim1, 102=Jim, 104=Jim, 106=Jim2}
/*
* TreeMap
* 1 TreeMap中的所有元素都保持着某种固定的顺序
* 2 适用于按照自然顺序或自定义顺序遍历键
* 3 键(key)是有序的
* 4 key值所在的类必须实现comparable接口,重写compareTo方法
* 5 TreeMap根据compareTo的逻辑,对key进行排序
* 6 键是红黑树结构,保证了键的排序和唯一性
*/
}
}
实现类:Hashtable
Hashtable和HashMap的底层实现基本是一样的,但是Hashtable是线程安全的,添加了同步锁:synchronized。底层实现是:哈希表+单链表。
重点讲一下HashMap和Hashtable的区别
HashMap | Hashtable |
---|---|
非线程安全 | 线程安全,添加了同步锁synchronized |
只包含containsKey和containsValue方法 | 同时保留了contains方法 |
允许有一个空值 | 不允许有空值 |
父类AbstractMap | 父类Dictionary(已废弃) |
Map接口的集合遍历
根据键找值
1、获取所有键的集合。
2、遍历键的集合,获取到每一个键。
3、根据键找值。
代码示例:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class KeySetDemo {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(100,"Jim0");
map.put(101,"Jim1");
map.put(102,"Jim2");
map.put(103,"Jim3");
map.put(104,"Jim4");
System.out.println(map);
Set<Integer> keyset = map.keySet();
for (Integer i:keyset) {
System.out.print(map.get(i)+"\t");
}
}
}
根据键值对对象找键和值
1、获取所有键值对对象的集合。
2、遍历键值对对象的集合,获取到每一个键值对对象。
3、根据键值对对象找键和值。
代码示例
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class EntrySetDemo {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(100,"Jim0");
map.put(101,"Jim1");
map.put(102,"Jim2");
map.put(103,"Jim3");
map.put(104,"Jim4");
System.out.println(map);
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
for (Map.Entry<Integer,String> e:entrySet) {
System.out.println(e.getKey()+"====="+e.getValue());
}
}
}
Collections类
概述
1、Collections是集合类的工具类,与数组中的工具类Arrays类似。
2、定义了大量的静态方法:
(1)同步集合对象的方法。
(2)对List排序的方法。
Collections的使用
import java.util.ArrayList;
import java.util.Collections;
public class CollectionsDemo {
public static void main(String[] args) {
/*
* Colletions类是集合类的工具类,与数组的工具类Arrays类似
* 定义了大量的静态方法:
* 1.同步集合对象的方法
* 2.对List排序的方法
*/
ArrayList<String> arrayList = new ArrayList<>();
//向list结合中添加一个可变长度的实参
String [] str = {
"a","s","b","e"};
Collections.addAll(arrayList,str);
Collections.addAll(arrayList,"s","a","b");
System.out.println(arrayList);//[a, s, b, e, s, a, b]
//排序
Collections.sort(arrayList);
System.out.println(arrayList);//[a, a, b, b, e, s, s]
//二分搜索
System.out.println(Collections.binarySearch(arrayList,"b"));//3
//copy(list1,list2)将list2中的数据copy到list1中,list1必须大于等于list2
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,str);
Collections.addAll(list,"x","x","x","x");
System.out.println(list);//[a, s, b, e, x, x, x, x]
Collections.copy(list,arrayList);
System.out.println(list);//[a, a, b, b, e, s, s, x]
//反转
Collections.reverse(list);
System.out.println(list);
//填充集合
Collections.fill(arrayList,"x");
System.out.println(arrayList);
//求集合的最大值
System.out.println(Collections.max(list));
//交换位置
Collections.swap(list,3,5);
System.out.println(list);
}
}