Map集合
Map集合概述
一.Map接口概述
- java.util包下的,使用时需要导包
- 将键映射到值得对象
- 一个映射不能包含重复的键
- 每个键最多只能映射到一个值
二.Map接口和Collection接口的不同
- Map是双列的,Collection是单列的
- Map的键唯一,Collection的子体系Set是唯一的
- Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
Map集合的功能概述
1.添加功能
- V put(K key,V value):添加元素
如果键是第一次存储,就直接存储元素,返回null
如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
2.删除功能
- void clear(): 移除所有的键值对元素
- V remove(Object key):根据键删除删除键值对元素,并把值返回
3.判断功能
- boolean containsKey(Object key):判断集合是否包含指定的键
- boolean containsValue(Object value):判断集合是否包含指定的值
- boolean isEmpty():判断集合是否为空
4.获取功能
- Set<Map.Entry<K,V>> entrySet():(Map.Entry<K,V>泛型) 获取键值对对象
- V get(Object key):根据键获取值
- Set KeySet():获取集合中所有键的集合
- Collection values():获取集合中所有值的集合
案例演示
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Demo1_Map {
public static void main(String[] args) {
//demo1();
//demo2();
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("赵六", 26);
Collection<Integer> c = map.values();
System.out.println(c); //[24, 23, 25, 26]存储不按顺序,每次运行结果不同
System.out.println(map.size()); //4
}
public static void demo2() {
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("赵六", 26);
//Integer value = map.remove("张三"); //根据键删除元素,返回键对应的值
//System.out.println(value);
System.out.println(map.containsKey("张三"));//判断是否包含传入的键true
System.out.println(map.containsValue(23)); //判断是否包含传入的值true
System.out.println(map);
}
public static void demo1() {
Map<String, Integer>map = new HashMap<>();
Integer i1 = map.put("张三", 23); //覆盖的值23
Integer i5 = map.put("张三", 26); //相同的键("张三")不存储,值(23)覆盖,返回被覆盖的值
Integer i2 = map.put("李四", 24);
Integer i3 = map.put("王五", 25);
Integer i4 = map.put("赵六", 26);
System.out.println(map);
System.out.println(i1);
System.out.println(i2);
System.out.println(i3);
System.out.println(i4);
System.out.println(i5);//23
}
}
Map集合遍历之键找值
1.通过查看Map集合的API发现没有iterator方法,那么双列集合如何迭代呢?
- 使用增强for循环遍历
- 根据键获取值
案例演示
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo2_Iterator {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("赵六", 26);
Set<String> keySet = map.keySet(); //获取所有键的集合
Iterator<String> it = keySet.iterator();
while (it.hasNext()) { //判断集合中是否有元素
String key = it.next(); //获取每一个元素
Integer value = map.get(key); //根据键获取值
System.out.println(key + "=" + value);
}
//使用增强for循环遍历
/*for (String key : map.keySet()) {
System.out.println(key + "=" + map.get(key));
}*/
}
}
Map集合遍历之键值对对象找键和值
1.解释Map.Entry
- Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并存储在Set集合中
2.方法
- 增强for循环
- 键值对对象找键和值
案例演示
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo3_Iterator {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("赵六", 26);
/*//Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并存储在Set集合中
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
//获取每一个对象
Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
while (it.hasNext()) {
//获取每一个Entry对象
Map.Entry<String, Integer> en = it.next();
String key = en.getKey();
Integer value = en.getValue();
System.out.println(key + "=" + value);
}*/
//增强for循环
for (Map.Entry<String,Integer> en : map.entrySet()) {
System.out.println(en.getKey() + "=" + en.getValue());
}
}
}
HashMap集合键是Student,值是String
- 键是学生对象,代表每一个学生
- 值是字符串对象,代表学生归属地
案例演示
import java.util.HashMap;
import com.heima.bean.Student;
public class Demo5_HashMap {
public static void main(String[] args) {
HashMap<Student, String> hm = new HashMap<>();
hm.put(new Student("张三",23),"北京");//往HashSet集合中存储时要在Student类中重写其中的hashCode()与equals()方法
hm.put(new Student("张三",23),"上海");//如果不重写会存储重复元素
hm.put(new Student("李四",24),"广州");
hm.put(new Student("王五",25),"深圳");
System.out.println(hm);
//{Student [name=张三, age=23]=上海, Student [name=李四, age=24]=广州, Student [name=王五, age=25]=深圳}因为键不是第一次存储所以用上海把北京替换掉
}
}
LinkedHashMap
一.特点
- 底层是链表实现的,可以保证怎么存就怎么取
TreeMap集合键是Student,值是String
1.自然顺序(Comparable)
- 在Student类中重写compareTo()方法,定义比较方式
@Override
public int compareTo(Student o) {
int num = this.age - o.age;//以年龄排序
return num == 0 ? this.name.compareTo(o.name) : num;
}
2.比较器顺序(Comparator)
- 创建TreeSet的时候传入Comparator的子类对象,或者传入匿名内部类重写compare()方法
TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getName().compareTo(s2.getName());//按姓名比较
return num == 0 ? s1.getAge() - s2.getAge() : num;
}
});
案例演示
import java.util.Comparator;
import java.util.TreeMap;
import com.heima.bean.Student;
public class Demo7_TreeMap {
public static void main(String[] args) {
//demo1();
TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getName().compareTo(s2.getName());//按姓名比较
return num == 0 ? s1.getAge() - s2.getAge() : num;
}
});
tm.put(new Student("张三",23), "北京");
tm.put(new Student("李四",24), "上海");
tm.put(new Student("王五",25), "广州");
tm.put(new Student("赵六",26), "深圳");
System.out.println(tm);//按姓输出 张 李 王 赵
}
public static void demo1() {
TreeMap<Student, String> tm = new TreeMap<>();
tm.put(new Student("张三",23), "北京");
tm.put(new Student("李四",24), "上海");
tm.put(new Student("王五",25), "广州");
tm.put(new Student("赵六",26), "深圳");
System.out.println(tm);//按年龄排序输出的
}
}
集合嵌套之HashMap嵌套HashMap
一. 需求:
双园课堂
- 第88期第99期两个基础班定义成一个双列集合,键是学生对象,值是学生归属地
- 不论88还是99班级都是班级对象,所以为了统一管理,把这些对象都添加到双园课堂集合中
案例演示
import java.util.HashMap;
import com.heima.bean.Student;
public class Demo8_HashMap_HashMap {
/*
集合嵌套之HashMap嵌套HashMap
需求:
双园课堂
第88期第99期两个基础班定义成一个双列集合,键是学生对象,值是学生归属地
不论88还是99班级都是班级对象,所以为了统一管理,把这些对象都添加到双园课堂集合中
*/
public static void main(String[] args) {
HashMap<Student, String> hm88 = new HashMap<>();
hm88.put(new Student("张三",23), "北京");
hm88.put(new Student("李四",24), "北京");
hm88.put(new Student("王五",25), "上海");
hm88.put(new Student("赵六",26), "广州");
HashMap<Student, String> hm99 = new HashMap<>();
hm99.put(new Student("唐僧",1023), "北京");
hm99.put(new Student("孙悟空",1024), "北京");
hm99.put(new Student("猪八戒",1025), "上海");
hm99.put(new Student("沙和尚",1026), "广州");
HashMap<HashMap<Student, String>, String> hm = new HashMap<>();
hm.put(hm88, "第88期基础班");
hm.put(hm99, "第99期基础班");
//遍历双列集合
for ( HashMap<Student, String> key1 : hm.keySet()) {//hm.keySet()代表的是双列集合中键的集合
String value1 = hm.get(key1); //根据键对象获取值
//遍历键的双列集合对象
for (Student key2 : h.keySet()) { //h.keySet()是获取集合中所有的学生
String value2 = h.get(key2);
System.out.println(key2 + " = " + value2 + " = " + value1);
}
}
}
}
面试题:HashMap和Hashtable的区别
一.共同点:
- 底层都是哈希算法,都是双列集合
二.区别:
区别1:
- HashMap是线程不安全的,效率高,JDK1.2版本的
- Hashtable是线程安全的,效率低,JDK1.0版本的
区别2:
- HashMap可以存储null键和null值
- Hashtable不可以存储null键和null值
案例演示
import java.util.HashMap;
import java.util.Hashtable;
public class Demo9_Hashtable {
public static void main(String[] args) {
HashMap<String, Integer> hm = new HashMap<>();
hm.put(null, 23);
hm.put("张三", null);
System.out.println(hm);
Hashtable<String, Integer> ht = new Hashtable<>();
// ht.put(null, 23); 报错java.lang.NullPointerException
// ht.put("张三", null);
// System.out.println(ht);
}
}
Collections工具类
一.Collectiion类的概述
- 针对集合操作的工具类
二.Collections成员方法
- public static void sort(List list):对List集合排序
- public static int binarySearch(List<?> list,T key):二分查找
- public static T max(Collection<?> coll):根据默认排序结果获取集合中的最大值
- public static void reverse(List<?> list):反转集合
- public static void shuffle(List<?> list):随机置换,可以用来洗牌
案例演示
import java.util.ArrayList;
import java.util.Collections;
public class Demo1_Collections {
public static void main(String[] args) {
//demo1();
//demo2();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("d");
list.add("f");
list.add("g");
System.out.println(Collections.max(list)); //根据默认排序结果获取集合中的最大值
Collections.reverse(list); //反转集合
System.out.println(list);
Collections.shuffle(list); //随机置换,可以用来洗牌
System.out.println(list);
}
public static void demo2() {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("f");
list.add("d");
list.add("g");
System.out.println(Collections.binarySearch(list, "c"));//1
System.out.println(Collections.binarySearch(list, "b"));
//-2 因为集合中不存在b所以按照集合顺序应该在a后c前插入,索引为1 ,-2 = 插入点索引 - 1
System.out.println(Collections.binarySearch(list, "e"));//-3
}
public static void demo1() {
ArrayList<String> list = new ArrayList<>();
list.add("c");
list.add("a");
list.add("a");//重复保留
list.add("b");
list.add("d");
System.out.println(list);
Collections.sort(list);//对List集合排序
System.out.println(list);
}
}
模拟斗地主
一.分析
- 创建HashMap集合,键存储索引,值存储牌的属性
- 创建ArrayList集合存储索引,洗牌则为洗索引
- 洗牌:通过Collections中的shuffle()方法
- 创建TreeSet集合存储代表三个人和底牌,因为TreeSet集合会自动对索引进行排序
- 发牌
- 看牌,ArrayList中存储的索引找HashMap中的值
案例演示
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
public class Test3 {
public static void main(String[] args) {
String[] num = {"3","4","5","6","7","8","9","10","J","Q","K","A","2",};//按顺序放
String[] color = {"红桃","黑桃","方片","梅花"};
HashMap<Integer, String> hm = new HashMap<>(); //存储索引和值
ArrayList<Integer> list = new ArrayList<>(); //存储索引
int index = 0;
//拼接扑克牌并将索引存储在HashMap中
for (String s1 : num) { //获取数字
for (String s2 : color) { //获取花色
hm.put(index, s2.concat(s1));
list.add(index); //将索引添加到list集合中
index++;
}
}
//将大小王添加
hm.put(index, "小王");
list.add(index);
index++;
hm.put(index, "大王");
list.add(index);
//洗牌
Collections.shuffle(list); //洗索引
//发牌
TreeSet<Integer> gaojin = new TreeSet<>();
TreeSet<Integer> longwu = new TreeSet<>();
TreeSet<Integer> me = new TreeSet<>();
TreeSet<Integer> dipai = new TreeSet<>();
for (int i = 0; i < list.size(); i++) {
if (i >= list.size() - 3) {
dipai.add(list.get(i));
} else if (i % 3 == 0) {
gaojin.add(list.get(i));
} else if (i % 3 == 1) {
longwu.add(list.get(i));
} else {
me.add(list.get(i));
}
}
//看牌
lookPoker(hm, gaojin, "高进");
lookPoker(hm, longwu, "龙武");
lookPoker(hm, me, "雷佳辉");
lookPoker(hm, dipai, "底牌");
}
public static void lookPoker(HashMap<Integer, String> hm,TreeSet<Integer> ts,String name) {
System.out.println(name + "的牌是:");
for (Integer i : ts) {
System.out.print(hm.get(i) + " ");
}
System.out.println();
}
}
泛型固定上下边界
一.泛型固定下边界
- 泛型固定下边界
二.泛型固定上边界
- ? extends E
案例演示
import java.util.ArrayList;
import java.util.Comparator;
import java.util.TreeSet;
import com.heima.bean.BaseStudent;
import com.heima.bean.Student;
public class Demo2_Genric {
public static void main(String[] args) {
//demo1();
TreeSet<Student> ts1 = new TreeSet<>(new CompareByAge());
ts1.add(new Student("张三",33));
ts1.add(new Student("李四",13));
ts1.add(new Student("王五",23));
ts1.add(new Student("赵六",43));
TreeSet<BaseStudent> ts2 = new TreeSet<>(new CompareByAge());
ts2.add(new BaseStudent("张三",33));
ts2.add(new BaseStudent("李四",13));
ts2.add(new BaseStudent("王五",23));
ts2.add(new BaseStudent("赵六",43));
System.out.println(ts1);
System.out.println(ts2); //子类BaseStudent可以用父类Student的比较器
}
public static void demo1() {
//? extends E
ArrayList<Student> list1 = new ArrayList<>();
list1.add(new Student("张三",23));
list1.add(new Student("李四",24));
ArrayList<BaseStudent> list2 = new ArrayList<>();
list2.add(new BaseStudent("王五",25));
list2.add(new BaseStudent("赵六",26));
list1.addAll(list2); //可将子类的集合对象添加到父类集合中
System.out.println(list1);
}
}
class CompareByAge implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge();
return num == 0 ? s1.getName().compareTo(s2.getName()) : num;
}
}