一、Map
(一)概述
1、Map,地图,地图上的每一个坐标都和现实生活中一个实际的地方一一对应,有这种一对一的关系,这种对应关系是通过穷举的方式描述的。
2、Map集合描述的是一个数据到另一个数据的映射关系(对应关系)。其中一个数据:key,叫做键,有规律的,容易记忆的,比较简单。另一个数据:value,叫做值,往往没有规律,不容易记忆,比较复杂。
3、【绝大多数的双列集合的操作,都是根据key操作value】
4、映射:对应关系
(1)y = x * x
(2)穷举罗列:{1= 1, 4 = 2, 9 = 3, 16= 4, 25 = 5 }
5、【Map集合的特点】:key是唯一的,value可以重复,每一个key都只能唯一对应一个value
(二)Map中常用的方法
1、**put(K key,V value)**当键的值不存在的时候,向map集合中添加键值对,当键值存在时,根据键修改其对应的值
2、**get(Object key)**根据建获取其对应的值;如果键不存在,获取到的结果是null
3、**containsKey(Object key)**判断集合中键是否包含指定键
4、**containsValue(Object value)判断集合中是否包含指定值
(三)Map集合的第一种遍历方式
1、根据操作双列集合的思路:通过键来获取值,根据键获取其对应的值
2、方法:keySet() 获取map集合中所有键组成的Set集合
3、操作:
(1)调用keySet()**方法获取到map集合中所有的key添加到一个Set集合中
(2)遍历Set集合得到每一个key
(3)根据每个key得到其对应的值
4、可以结合 foreach 或者迭代器遍历
5、思路图示
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo02_PrintMapFisrtWay {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(123, "abc");
map.put(6666, "zzzzz");
map.put(73, "AA");
map.put(-87, "zxcvb");
map.put(4567, "wlq");
map.put(44, "iopuyg");
for(Integer key: map.keySet()) {
System.out.println(key + "=" + map.get(key));
}
}
public static void test2(Map<Integer, String> map) {
//1.调用keySet()方法,获取map集合的键集
Set<Integer> keySet = map.keySet();
//2.遍历set集合获取每一个键
for (Integer key : keySet) {
//3.根据key获取value
String value = map.get(key);
System.out.println(key + "=" + value);
}
}
public static void test1(Map<Integer, String> map) {
//1.调用keySet()方法,获取map集合的键集
Set<Integer> keySet = map.keySet();
//2.遍历键集
Iterator<Integer> it = keySet.iterator();
while (it.hasNext()) {
Integer key = it.next();
//3.将获取到的键,在map中获取其对应的值
String value = map.get(key);
System.out.println(key + "=" + value);
}
}
}
(四)Map集合的第二种遍历思路
1、Map集合中对于所有的键值对都是通过对象存储的,这个对象是Entry对象,一个Entry对象就包含一对键值对,我们可以将所有的键值对对象获取到,再从每个对象中分别拿去键和值
2、方法:entrySet() 返回一个Set集合,这个集合中包含了map集合中所有的键值对对象
3、操作:
(1)调用 **entrySet()方法获取Map结合的键值对对象的Set集合
(2)遍历Set集合获取到每一个键值对对象,即Entry对象
(3)Entry 对象调用Entry接口中的方法getKey()**和 getValue() 分别获取键和值
4、思路图示:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Demo03_PrintMapSecodWay {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(123, "abc");
map.put(6666, "zzzzz");
map.put(73, "AA");
map.put(-87, "zxcvb");
map.put(4567, "wlq");
map.put(44, "iopuyg");
for(Map.Entry<Integer, String> entry: map.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
public static void test2(Map<Integer, String> map) {
//1.调用entrySet()方法,获取存储键值对对象的Set集合
Set<Entry<Integer,String>> entrySet = map.entrySet();
//2.获取每一个entry对象
for (Entry<Integer, String> entry : entrySet) {
//3.从entry对象中获取键和值
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
public static void test1(Map<Integer, String> map) {
//1.调用entrySet()方法,获取存储键值对对象的Set集合
Set<Entry<Integer,String>> entrySet = map.entrySet();
//2.获取Set集合的迭代器对象
Iterator<Entry<Integer, String>> it = entrySet.iterator();
//3.迭代器获取entry对象
while (it.hasNext()) {
//4.获取到了具体的entry对象
Entry<Integer, String> entry = it.next();
//5.分别获取entry对象中的键和值
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
}
(五)练习
键盘录入一个字符串,统计每个字符出现的次数
例如,录入aaaabbccddd!@#@#KaTeX parse error: Expected 'EOF', got '#' at position 2: @#̲%cc66ff
打印出来:a有4个,b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Demo04_Exercise {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入字符串:");
String str = sc.nextLine();
Map<Character, Integer> map = getCharacterNumber(str);
System.out.println(getStringResult(map));
}
public static String getStringResult(Map<Character, Integer> map) {
StringBuilder sb = new StringBuilder();
//遍历map集合
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
sb.append(entry.getKey()).append("有").append(entry.getValue()).append("个,");
}
String str = sb.toString();
return str.substring(0, str.length() - 1);
}
/**
* 统计字符串中字符的数量
*/
public static Map<Character, Integer> getCharacterNumber(String str) {
//使用map集合进行字符数量的统计
Map<Character,Integer> map = new HashMap<>();
//我有字符串,我得统计字符
//String -> char
char[] arr = str.toCharArray();
//遍历获取每一个字符
//aaaabbccddd!@#@#$@#$%cc66ff
for (char c : arr) {
//判断当前map集合中是否统计过当前字符
/*if(map.containsKey(c)) {
//如果已经统计过,就在原来的数量上+1
//1.根据键获取已经存在的值
Integer oldValue = map.get(c);
//2.旧的值基础上+1
int newValue = oldValue + 1;
//3.根据键,将原来的旧数量替换为新的数量
map.put(c, newValue);
} else {
//没有统计过,就意味着第一次遇到,就添加到map中
map.put(c, 1);
}*/
map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
}
return map;
}
}
二、实现类
(一)HashMap
1、是Map接口的一个实现类,底部是哈希表
2、HashMap的键是无序的
3、HashMap对JDK类型的元素可以自动去重
4、HashMap对定义类型的元素做键,无法去重,需要重写HashCode和equals方法,原理和HashSet一致
5、HashMap和HashSet的关系:
(1)HashSet是由HashMap实现的
(2)实际上HashMap隐藏值的那一列,保留键的一列,就是HashSet
(二)HashMap和Hashtable的区别
1、相同点:都是双列集合,都是Map接口的实现类,底部都是哈希表,维护的都是映射关系
2、不同点:
(1)存值方面:HashMap允许存储null键和null值,Hashtable不允许
(2)线程安全:HashMap不安全,Hashtable不安全
(3)效率方面:HashMap效率高,Hashtable效率低
(4)版本不同:HashMap出现在JDK1.2,Hashtable出现在JDK1.0
(三)LinkedHashMap
1、是HashMap的子类
2、和HashMap的区别之一在于LinkedHashMap具有可预知的迭代顺序,即存取顺序一致
三、Collections工具类
1、binarySearch(List<? extends Comparable<? super T>> list, T key) 在指定的List集合中查找指定的元素并返回索引,但是使用前需要通过sort(List list) 对集合排序。如果没有进行排序,返回的结果不确定;如果查找的元素不存在,返回**(-(插入点)-1)**
2、sort(List list) 对集合元素进行升序排序
3、fill(List<? super T> list, T obj) 使用指定元素,替换集合中所有的元素
4、frequency(Collection<?> c, Object o) 在指定集合中查找指定元素的个数
5、max(Collection<? extends T> coll) 返回指定集合中的最大值
6、min(Collection<? extends T> coll) 返回指定集合中的最小值
7、replaceAll(List list, T oldVal, T newVal) 在指定集合中,使用新的值,去替换指定的旧的值
8、reverse(List<?> list) 反转集合
9、swap(List<?> list, int i, int j) 交换集合中指定两元素的位置
10、shuffle(List<?> list) 洗牌
11、synchronizedXXX系列方法,将线程不安全的集合传入,返回一个线程安全的集合
12、unmodifiableXXX系列方法,将集合传入,返回集合的只读视图