1 Map<K,V>接口
1.1 特点
- 双列集合一个元素包含俩值
- Key不可以重复,Value可以重复
- Key和Value一一对应
- Key和Value可以时任意类型
1.2 常用方法
public V put(K key, V value): 不重复返回null,重复返回value
public static void main(String[] args) {
Map<String, Integer> persons = new HashMap<>();
persons.put("张三",19);
Integer out1 = persons.put("李四", 20);
Integer out2 = persons.put("李四", 30);
System.out.println(out1);//不重复返回null
System.out.println(out2);//重复返回原来的value=20
System.out.println(persons);//{李四=30, 张三=19}
}
public V remove(Object Key):指定键,删除键值对,返回删除键对应的值,键不存在则返回null
public static void main(String[] args) {
Map<String, Integer> persons = new HashMap<>();
persons.put("张三",19);
persons.put("李四", 20);
Integer out1 = persons.remove("张三");
System.out.println(persons);//{李四=20}
System.out.println(out1);//19
Integer out2 = persons.remove("王五");
System.out.println(out2);//null
}
public V get(Object Key):通过键来获取值
public static void main(String[] args) {
Map<String, Integer> persons = new HashMap<>();
persons.put("张三",19);
System.out.println(persons.get("张三"));//19
System.out.println(persons.get("李四"));//null
}
public boolean containsKey(Object Key):键是否存在
public static void main(String[] args) {
Map<String, Integer> persons = new HashMap<>();
persons.put("张三",19);
System.out.println(persons.containsKey("张三"));//true
System.out.println(persons.containsKey("李四"));//false
}
1.3 遍历Map集合
方法1:遍历键找值法
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三",19);
map.put("李四",20);
map.put("王五",21);
//1. 取出Map的所有key存在Set中
Set<String> set = map.keySet();
//2.1 while遍历set,获取key,map.get获取value
Iterator<String> it = set.iterator();
while(it.hasNext()){
String key = it.next();
Integer value = map.get(key);
System.out.println(key + " " + value);
}
//2.2 foreach法遍历
for(String key: set){
System.out.println(key + " " + map.get(key));
}
}
方法2: Entry键值对对象
Map接口中有一个内部接口Entry
作用:Map一创建,就在Map中创建一个Entry对象,用来记录键和值,得到二者的映射关系。(相当于结婚证)
- Set<Map.Entry<K, V>> entrySet() 把Map集合的多个Entry对象取出存在Set集合中。
- 遍历Set集合,获取每个Entry对象。
- getKey()获取Key,getValue()获取Value。
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三",19);
map.put("李四",20);
map.put("王五",21);
//1. 取出Map的所有entry对象存在Set中
Set<Map.Entry<String, Integer>>set = map.entrySet();
//2.1 while遍历set,获取entry,再分别getKey和Value
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while(it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " " + value);
}
//2.2 foreach法遍历
for(Map.Entry<String, Integer> entry: set){
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
2 Map接口的实现类—— HashMap
2.1 特点
- 底层是哈希表(JDK1.8后:数组+链表/红黑树) 查询快
- 无序集合,存取无序
2.2 存储自定义类型键值
注意:因为Map集合要保证Key是唯一的,所以作为Key的元素必须重写hashCode方法和equals方法,从而保证Key的唯一性。
public static void main(String[] args) {
Map<Person, Integer> map1 = new HashMap<Person, Integer>();
map1.put(new Person("李四",10),170);
map1.put(new Person("李四",10),180);
System.out.println(map1);
//重写前输出:{Person{name='李四', age=10}=180, Person{name='李四', age=10}=170}
//重写后输出:{Person{name='李四', age=10}=180}
}
3 HashMap的子类——LinkedHashMap
3.1 特点
- 底层是哈希表+链表 保证迭代顺序
- 有序集合,存取有序
3.2 使用示例
public static void main(String[] args) {
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("a",1);
map1.put("c",3);
map1.put("b",2);
System.out.println(map1);//存和取顺序不同 {a=1, b=2, c=3}
LinkedHashMap<String, Integer> map2 = new LinkedHashMap<>();
map2.put("a",1);
map2.put("c",3);
map2.put("b",2);
System.out.println(map2);//存和取顺序相同{a=1, c=3, b=2}
}
4 Map接口的实现类——Hashtable
4.1 Hashtable的特点
- 键和值都不可以为空。
- 最早的双列集合,JDK1.0就有。
- 它是单线程的,同步的,线程安全,速度慢。
- 底层是一个哈希表。
- 和vector(ArrayList)一样再JDK1.2后被HashMap取代了。
- Hashtable的子类Properties集合是唯一一个和IO流结合的集合。【仍活跃】
4.2 示例
public static void main(String[] args) {
Hashtable<String,String> ht = new Hashtable<>();
HashMap<String, String> hm = new HashMap<>();
hm.put(null,null);
hm.put("a",null);
hm.put(null,"b");
System.out.println(hm);//{null=b, a=null}
// ht.put(null,null);
// 报错:java.lang.NullPointerException
}
5 Map集合练习
5.1 统计字符出现次数
遍历字符串:charAt加索引遍历 / toCharArray转为数组
for(int i = 0; i < str.length(); i++) —> str.charAt(i)
for(char c: str.toCharArray()) —> c
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
Map<Character, Integer> map = new HashMap<>();
char[] strArray = str.toCharArray();
for (int i = 0; i < strArray.length; i++) {
if(!map.containsKey(strArray[i])){
map.put(strArray[i],1);
}else{
int value = map.get(strArray[i]);
map.put(strArray[i],++value);
}
}
System.out.println(map);
}
5.2 斗地主升级版-玩家牌有序
public static void main(String[] args) {
//1. 准备牌面
String[] colors = {"♥","♠","♦","♣"};
String[] nums = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
HashMap<Integer, String> pocker = new HashMap<>();
pocker.put(0,"BK");
pocker.put(1,"SK");
int count = 2;
for(String num: nums){
for(String color: colors){
pocker.put(count++,color+num);
}
}
System.out.println(pocker);
//2. 洗牌:打乱编号
Set<Integer> set = pocker.keySet();
ArrayList<Integer> list = new ArrayList<>();
list.addAll(set);
Collections.shuffle(list);
ArrayList<Integer> left = new ArrayList<>();
ArrayList<Integer> p1 = new ArrayList<>();
ArrayList<Integer> p2 = new ArrayList<>();
ArrayList<Integer> p3 = new ArrayList<>();
for (int i = 0; i < pocker.size(); i++) {
Integer p = list.get(i);
if(i>=51){
left.add(p);
}else{
if(i%3 == 0){
p1.add(p);
}else if(i%3 == 1){
p2.add(p);
}else{
p3.add(p);
}
}
}
//3. 发牌:对编号排序 取出标号对应的值
Collections.sort(p1);
Collections.sort(p2);
Collections.sort(p3);
Collections.sort(left);
ArrayList<String> player1 = new ArrayList<String>();
ArrayList<String> player2 = new ArrayList<String>();
ArrayList<String> player3 = new ArrayList<String>();
ArrayList<String> dipai = new ArrayList<String>();
for(Integer i : p1){
player1.add(pocker.get(i));
}
for(Integer i : p2){
player2.add(pocker.get(i));
}
for(Integer i : p3){
player3.add(pocker.get(i));
}
for(Integer i : left){
dipai.add(pocker.get(i));
}
//4. 看牌
System.out.println(player1);
System.out.println(player2);
System.out.println(player3);
System.out.println(dipai);
}
6 JDK9对集合添加的优化
Java9中添加了几种集合工厂方法,更方便创建少量元素的集合、map实例。新的List、Set、Map的静态工厂方法可以更方便地创建集合的不可变实例。
使用前提:集合中存储的元素个数已经确定,不再改变时使用
注意:
- 只适用于List、Set、Map三个接口
- 它是不能改变的集合,不可再用add和put
- 不可以在调用时含有相同元素