JavaSE学习总结(十四)Map集合/Map和Collection的区别/HashMap/LinkedHashMap/TreeMap/集合间的嵌套/Hashtable/Collections工具类
一、Map集合
我们知道,一个学号就能对应一个学生,并且每个学生的学号都不同,学号就像一个键,对应的学生就是该键对应的值。日常生活中经常能见到这种类似学号对应学生的例子。Java 为了我们更加方便地去操作,这种键值映射关系的数据,给我们提供了另外一种集合叫做Map集合。
(一)概述
public interface Map<K,V>
- 类型参数:
K - 此映射所维护的键的类型
V - 映射值的类型
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。 (键唯一,值不一定唯一)
常用子实现类:HashMap,Hashtable,LinkedHashMap,TreeMap,Properties
(二)Map接口和Collection接口的区别
- Map是双列的,Collection是单列的
- Map的键唯一,Collection的子体系Set的元素是唯一的
- Map集合的数据结构只针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
二、HashMap集合
HashSet 用的是HashMap来存的,因此我们可以知道HashMap的键的数据结构是哈希表。
HashMap 是基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。
(一)添加功能
V put(K key,V value)
:添加元素。
这个方法其实还有另一个功能:替换
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回被替换的值
案例演示1
import java.util.HashMap;
public class MyTest {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("Monday","星期一");
map.put("Tuesday","星期二");
map.put("Wednesday","星期三");
map.put("Thursday","星期四");
map.put("Friday","星期五");
map.put("Saturday","星期六");
map.put("Sunday","星期日");
System.out.println(map);
//当发生键相同的时候,值就会覆盖,返回的是旧值
String s = map.put("Today", "今天");
String s1 = map.put("Today", "今日");
System.out.println(s);
System.out.println(s1);
}
}
案例演示2
键是 String 类型 值是Student类型
import java.util.HashMap;
//学生类
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//测试类
public class MyTest {
public static void main(String[] args) {
HashMap<String, Student> map = new HashMap<>();
map.put("001",new Student("张三",23));
map.put("001",new Student("李四",23));
map.put("002",new Student("王五",22));
map.put("003",new Student("赵六",21));
System.out.println(map);
}
}
如果String类型的键存在重复的,只会存最后出现那个(覆盖)
案例演示3
键是Student类型 值是String类型
import java.util.HashMap;
public class MyTest {
public static void main(String[] args) {
HashMap<Student, String> map = new HashMap<>();
map.put(new Student("张三",23),"001");
map.put(new Student("张三",23),"002");
map.put(new Student("王五",22),"003");
map.put(new Student("赵六",21),"004");
System.out.println(map);
}
}
如果Student类型的键的内容存在重复,而都能存进去,这是为什么呢?因为每创建一个Student对象,地址值是不同的,即使元素相同。而如果我们重写了Student类的equals()
方法和hashCode()
方法就能做到不存重复的键。
(二)删除功能
void clear()
:移除所有的键值对元素
V remove(Object key)
:根据键删除键值对元素,并把值返回
案例演示
import java.util.HashMap;
public class MyTest {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1,"aaa");
hashMap.put(2, "ccc");
hashMap.put(3, "ddd");
hashMap.put(4, "eee");
hashMap.put(5, "fff");
//根据键移除这个键值对
hashMap.remove(4);//移除键为4的键值对
System.out.println(hashMap);
//清空集合中所有的元素
hashMap.clear();
System.out.println(hashMap);
}
}
(三)判断功能
boolean containsKey(Object key)
:判断集合是否包含指定的键
boolean containsValue(Object value)
:判断集合是否包含指定的值
boolean isEmpty()
:判断集合是否为空
案例演示
import java.util.HashMap;
public class MyTest {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "aaa");
hashMap.put(1, "bbb");
hashMap.put(2, "ccc");
hashMap.put(3, "ddd");
hashMap.put(4, "eee");
hashMap.put(5, "fff");
// HashMap允许使用 null 值和 null 键
hashMap.put(null,null);
System.out.println(hashMap.get(null));
//判断集合有没有1这个键
boolean b = hashMap.containsKey(1);
System.out.println(b);
//判断集合中有没有bbb这个值
boolean flag = hashMap.containsValue("bbb");
System.out.println(flag);
//判断集合是否为空
boolean b1 = hashMap.isEmpty();
System.out.println(b1);
}
}
(四)获取功能
Set<Map.Entry<K,V>> entrySet()
: 返回一个键值对对象的Set集合
V get(Object key)
:根据键获取值
Set<K> keySet()
:获取集合中所有键的集合
Collection<V> values()
:获取集合中所有值的集合
案例演示
- 遍历Map集合方式1
import java.util.HashMap;
import java.util.Set;
public class MyTest {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "bbb");
hashMap.put(2, "ccc");
hashMap.put(3, "ddd");
hashMap.put(4, "eee");
hashMap.put(5, "fff");
//获取集合中所有键的集合
Set<Integer> set = hashMap.keySet();
for (Integer key : set) {
System.out.println(key+"="+hashMap.get(key)); // V get(Object key):根据键获取值
}
}
}
- 遍历Map集合方式2
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyTest {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "bbb");
hashMap.put(2, "ccc");
hashMap.put(3, "ddd");
hashMap.put(4, "eee");
hashMap.put(5, "fff");
//entrySet() 获取键值对 对象 放到Set集合里面去
Set<Map.Entry<Integer, String>> entries = hashMap.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
Integer key = entry.getKey();//通过键值对对象去获取它的键
String value = entry.getValue();//通过键值对对象去获取它的值
System.out.println(key+"="+value);
}
}
}
(五)长度功能
int size()
:返回集合中的键值对的对数
案例演示
import java.util.HashMap;
public class MyTest {
public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "bbb");
hashMap.put(2, "ccc");
hashMap.put(3, "ddd");
hashMap.put(4, "eee");
hashMap.put(5, "fff");
System.out.println(hashMap.size());
}
}
三、LinkedHashMap集合
- LinkedHashMap的底层的数据结构是链表和哈希表,元素有序(存取顺序一致)并且唯一
- 元素的有序性由链表数据结构保证;唯一性由哈希表数据结构保证
- 允许 null 元素
注意:Map集合的数据结构只和键有关
案例演示
import java.util.LinkedHashMap;
import java.util.Set;
public class MyTest{
public static void main(String[] args) {
//键的数据结构是链表和哈希表,链表保证键有序,哈希表保证键唯一
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("aaa", "AAA");
linkedHashMap.put("aaa", "AAA2");
linkedHashMap.put("ccc", "CCC");
linkedHashMap.put("ddd", "DDD");
linkedHashMap.put("eee", "EEE");
Set<String> strings = linkedHashMap.keySet();
for (String key : strings) {
System.out.println(key + "===" + linkedHashMap.get(key));
}
}
}
四、TreeMap集合
- TreeMap的数据结构是红黑树,可保证键的排序和唯一性
- 排序分为自然排序和比较器排序
- 线程是不安全的效率比较高
- TreeMap 键不允许插入null
案例演示1
键是Integer类,值是String类
import java.util.Set;
import java.util.TreeMap;
public class MyTest {
public static void main(String[] args) {
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(10,"aaaa");
treeMap.put(100, "bbbb");
treeMap.put(1, "cccc");
treeMap.put(0, "dddd");
treeMap.put(1044, "eeee");
treeMap.put(1088, "ffff");
Set<Integer> integers = treeMap.keySet();
for (Integer integer : integers) {
System.out.println(integer+"=="+treeMap.get(integer));
}
}
}
案例演示2
键是String类,值是Integer类
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MyTest{
public static void main(String[] args) {
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("aaa", 111);
treeMap.put("ggg", 1110);
treeMap.put("d", 1119);
treeMap.put("sss", 1114);
treeMap.put("c", 1141);
treeMap.put("fff", 1161);
//同样也能实现排序,因为String也实现了Comparable接口并重写了compareTo()方法
Set<Map.Entry<String, Integer>> entries = treeMap.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"==="+value);
}
}
}
案例演示3
键是自定义的Student类,值是String类
自然排序:需要Student类实现Comparable接口并重写compareTo()方法
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
//学生类
class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
int num=this.age-o.age;
int num2=num==0?this.name.compareTo(o.name):num;
return num2;
}
}
public class MyTest {
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<>();
treeMap.put(new Student("张三", 23), "111");
treeMap.put(new Student("李四", 23), "222");
treeMap.put(new Student("王五", 21), "222");
treeMap.put(new Student("赵六", 24), "444");
treeMap.put(new Student("赵四", 20), "555");
treeMap.put(new Student("小明", 25), "666");
treeMap.put(new Student("小红", 22), "777");
Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"==="+value);
}
}
}
当然也可以使用比较器排序:
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MyTest {
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num=o1.getAge()-o2.getAge();
int num2=num==0?o1.getName().compareTo(o2.getName()):num;
return num2;
}
});
treeMap.put(new Student("张三", 23), "111");
treeMap.put(new Student("李四", 23), "222");
treeMap.put(new Student("王五", 21), "222");
treeMap.put(new Student("赵六", 24), "444");
treeMap.put(new Student("赵四", 20), "555");
treeMap.put(new Student("小明", 25), "666");
treeMap.put(new Student("小红", 22), "777");
Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"==="+value);
}
}
}
思考题:输入一个英文字符串,输出每个字母出现的次数。
import java.util.*;
public class MyTest {
public static void main(String[] args) {
System.out.println("请输入字符串:");
Scanner sc = new Scanner(System.in);
String s = sc.next();
TreeMap<Character, Integer> map = new TreeMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(!map.containsKey(c)){ //如果map集合不存在这个键,就加进去
map.put(c,1); //1表示c代表的字符出现一次
}else{ //如果map集合已经存在这个键
Integer integer = map.get(c);//就将这个键对应的值取出来加一
integer++;
map.put(c,integer);//再放进集合中,由于键相同,它会覆盖之前的
}
}
Set<Map.Entry<Character, Integer>> entries = map.entrySet();
for (Map.Entry<Character, Integer> entry : entries) {
System.out.println(entry.getKey()+"出现的次数是:"+entry.getValue());
}
}
}
五、集合间的嵌套
(一)HashMap嵌套HashMap
案例演示
普通班
张三 20
李四 22
尖子班
王五 21
赵六 23
解析:每个班是键,班里的同学信息是对应的值;而同学的名字又是键,同学的年龄是对应的值。
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyTest1 {
public static void main(String[] args) {
HashMap<String, Integer> ptb = new HashMap<>();
ptb.put("张三",20);
ptb.put("李四",22);
HashMap<String, Integer> jzb = new HashMap<>();
jzb.put("王五",21);
jzb.put("赵六",23);
HashMap<String, HashMap<String, Integer>> classMap= new HashMap<>();
classMap.put("普通班",ptb);
classMap.put("尖子班",jzb);
//遍历
Set<String> strings = classMap.keySet();
for (String string : strings) {
System.out.println(string);
HashMap<String, Integer> map = classMap.get(string);
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println("\t"+entry.getKey()+" "+entry.getValue());
}
}
}
}
(二)HashMap嵌套ArrayList
案例演示
三国演义
吕布
周瑜
笑傲江湖
令狐冲
林平之
神雕侠侣
郭靖
杨过
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyTest1{
public static void main(String[] args) {
ArrayList<String> sanGuo = new ArrayList<>();
sanGuo.add("吕布");
sanGuo.add("周瑜");
ArrayList<String> xiaoAo = new ArrayList<>();
xiaoAo.add("令狐冲");
xiaoAo.add("林平之");
ArrayList<String> shenDiao = new ArrayList<>();
shenDiao.add("郭靖");
shenDiao.add("杨过");
HashMap<String, ArrayList<String>> map = new HashMap<>();
map.put("三国演义",sanGuo);
map.put("笑傲江湖",xiaoAo);
map.put("神雕侠侣",shenDiao);
//遍历
Set<Map.Entry<String, ArrayList<String>>> entries = map.entrySet();
for (Map.Entry<String, ArrayList<String>> entry : entries) {
System.out.println(entry.getKey());
ArrayList<String> value = entry.getValue();
for (String s : value) {
System.out.println("\t"+s);
}
}
}
}
(三)ArrayList嵌套HashMap
案例演示
周瑜---小乔
吕布---貂蝉
郭靖---黄蓉
杨过---小龙女
令狐冲---任盈盈
林平之---岳灵珊
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MyTest1{
public static void main(String[] args) {
HashMap<String, String> sanGuo = new HashMap<>();
sanGuo.put("吕布","貂蝉");
sanGuo.put("周瑜","小乔");
HashMap<String, String> xiaoAo = new HashMap<>();
xiaoAo.put("令狐冲","任盈盈");
xiaoAo.put("林平之","岳灵珊");
HashMap<String, String> shenDiao = new HashMap<>();
shenDiao.put("郭靖","黄蓉");
shenDiao.put("杨过","小龙女");
ArrayList<HashMap<String, String>> list = new ArrayList<>();
list.add(sanGuo);
list.add(xiaoAo);
list.add(shenDiao);
//遍历
for (HashMap<String, String> map : list) {
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+"---"+entry.getValue());
}
}
}
}
六、HashMap和Hashtable的区别
用法都一样
HashMap: 线程不安全,效率高,允许null值和null键
Hashtable: 线程安全,效率低,不允许null值和null键
七、Collections工具类
数组有个Arrays工具类,集合也有个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)
: 随机置换
案例演示
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
public class MyTest1 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
list.add(1002);
list.add(1030);
list.add(1050);
list.add(1040);
//list.sort();
//升序排序
Collections.sort(list);
//降序排序
//Collections.sort(list, new Comparator<Integer>() {
// @Override
// public int compare(Integer o1, Integer o2) {
// return 0;
// }
//});
System.out.println(list);
//二分查找
int i = Collections.binarySearch(list, 1050);
System.out.println(i);
//最大最小值
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
//反转集合中的元素
Collections.reverse(list);
System.out.println(list);
//随机打乱集合中元素的顺序
Collections.shuffle(list);
System.out.println(list);
}
}
模拟斗地主发牌洗牌整牌
import java.util.*;
public class MyTest {
public static void main(String[] args) {
//所有牌的集合
//为了方便给牌排序,定义一个map集合(键是序号,值是具体牌)
HashMap<Integer, String> pokerBox = new HashMap<>();
//为了方便给牌排序,定义一个ArrayList集合装牌的序号
ArrayList<Integer> indexs = new ArrayList<>();
int index=0;
String[] colors={"♠","♥","♦","♣"};
String[] nums={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
for (String num : nums) {
for (String color : colors) {
pokerBox.put(index,num.concat(color));//数字拼接花色
indexs.add(index);
index++;
}
}
pokerBox.put(index,"小王");
indexs.add(index);
index++;
pokerBox.put(index,"大王");
indexs.add(index);
index++;
//洗牌
Collections.shuffle(indexs);
//定义三位玩家(用TreeSet是因为存牌的序号进去自然就排好序了)
TreeSet<Integer> duWang = new TreeSet<>();
TreeSet<Integer> duShen = new TreeSet<>();
TreeSet<Integer> duXia = new TreeSet<>();
//定义三张地主底牌
TreeSet<Integer> diPai = new TreeSet<>();
//发牌
//赌王 0 3 6...(对3取余为0)
//赌神 1 4 7...(对3取余为1)
//赌侠 2 5 8...(对3取余为2)
//底牌是最后三张
for (int i = 0; i < indexs.size(); i++) {
if(i>=indexs.size()-3){
diPai.add(indexs.get(i));
}else if(i%3==0){
duWang.add(indexs.get(i));
}else if(i%3==1){
duShen.add(indexs.get(i));
}else if(i%3==2){
duXia.add(indexs.get(i));
}
}
//看牌
showPoker("赌王",duWang,pokerBox);
showPoker("赌神",duShen,pokerBox);
showPoker("赌侠",duXia,pokerBox);
showPoker("底牌",diPai,pokerBox);
}
public static void showPoker(String name,TreeSet<Integer> set,HashMap<Integer,String> pokerBox){
System.out.print(name+":");
//以TreeSet中的数字为键,找到map里对应的值
for (Integer integer : set) {
System.out.print(pokerBox.get(integer)+" ");
}
System.out.println();
}
}
集合小结