版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
18.01_集合框架(Map集合概述和特点)
- A:Map接口概述
- 查看API可以知道:
- 将键映射到值的对象
- 一个映射不能包含重复的键
- 每个键最多只能映射到一个值
- B:Map接口和Collection接口的不同
- Map是双列的,Collection是单列的
- Map的键唯一,Collection的子体系Set是唯一的
- Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
18.02_集合框架(Map集合的功能概述)
- A:Map集合的功能概述
- a:添加功能
- V put(K key,V value):添加元素。
- 如果键是第一次存储,就直接存储元素,返回null
- 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
System.out.println(map);
//{李四=24, 张三=23, 王五=25, 赵六=26}
}
}
- b:删除功能
- void clear():移除所有的键值对元素
- V remove(Object key):根据键删除键值对元素,并把值返回
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
Integer i = map.remove("张三");
System.out.println(i);//23
System.out.println(map);
//{李四=24, 王五=25, 赵六=26}
}
}
- c:判断功能
- boolean containsKey(Object key):判断集合是否包含指定的键
- boolean containsValue(Object value):判断集合是否包含指定的值
- boolean isEmpty():判断集合是否为空
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
Integer i = map.remove("张三");
System.out.println(i);//23
System.out.println(map.containsKey("张三"));//false 判断是否包含传入的键
System.out.println(map.containsValue(25));//true 判断是否包含传入的值
System.out.println(map);
//{李四=24, 王五=25, 赵六=26}
}
}
- d:获取功能
- Set<Map.Entry<K,V>entrySet():
- V get(Object key):根据键获取值
- Set<KkeySet():获取集合中所有键的集合
- Collection<Vvalues():获取集合中所有值的集合
- e:长度功能
- int size():返回集合中的键值对的个数
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
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
}
}
18.03_集合框架(Map集合的遍历之键找值)
- A:键找值思路:
- map集合不能直接迭代,没有Iterator方法
- 获取所有键的集合
- 遍历键的集合,获取到每一个键
- 根据键找值
- B:案例演示
- Map集合的遍历之键找值
- 使用迭代器遍历
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* 通过查看Map集合的方法发现Map集合没有iterator方法,那么双列集合的迭代如下
*/
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
Integer i = map.get("张三");//根据键获取值
System.out.println(i);//23
//要遍历首先获取所有的键
Set<String> set = map.keySet();//获取所有键的集合
Iterator<String> it = set.iterator();//获取迭代器
while(it.hasNext()){//判断集合中是否有元素
String key = it.next(); // 获取每一个键
Integer value = map.get(key); //根据键或取钱值
System.out.print(key +" "+ value +" ");
//李四 24 张三 23 王五 25 赵六 26
}
}
}
- 使用增强for循环遍历
import java.util.HashMap;
import java.util.Map;
/**
* 通过查看Map集合的方法发现Map集合没有iterator方法,那么双列集合的迭代如下
*/
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
Integer i = map.get("张三");//根据键获取值
System.out.println(i);//23
for (String key : map.keySet()) { //map.keySet是索引的键的集合
System.out.print(key +" "+ map.get(key) +" ");
//李四 24 张三 23 王五 25 赵六 26
}
}
}
18.04_集合框架(Map集合的遍历之键值对对象找键和值)
- A:键值对对象找键和值思路:
- 获取所有键值对对象的集合
- 遍历键值对对象的集合,获取到每一个键值对对象
- 根据键值对对象找键和值
- B:案例演示
- Map集合的遍历之键值对对象找键和值
import java.util.HashMap;
import java.util.Map;
/**
* 通过查看Map集合的方法发现Map集合没有iterator方法,那么双列集合的迭代如下
*/
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
//1.用迭代器的方法
// //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()){
// Map.Entry<String,Integer> en = it.next();
// String key = en.getKey(); //根据键值对象获取键
// Integer value = en.getValue(); //根据键值对象获取值
// System.out.print(key+" "+value+" ");
// //李四 24 张三 23 王五 25 赵六 26
// }
//2.用增强for循环的方法
for (Map.Entry<String,Integer> en : map.entrySet()) {
System.out.print(en.getKey()+" "+en.getValue()+" ");
//李四 24 张三 23 王五 25 赵六 26
}
}
}
- C:源码分析
18.05_集合框架(HashMap集合键是Student值是String的案例)
- A:案例演示
- HashMap集合键是Student值是String的案例
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(){
super();
}
public Student(String name,int age){
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
import java.util.HashMap;
import java.util.Map;
public class Main {
/**
* 键是学生对象,代表每一个学生
* 值是字符串对象,代表学生归属地
* @param args
*/
public static void main(String[] args) {
Map<Student,String> hm = new HashMap<>();
hm.put(new Student("张三",23),"北京");
hm.put(new Student("张三",23),"上海");
hm.put(new Student("李四",23),"广州");
hm.put(new Student("王五",23),"深圳");
System.out.println(hm);
//{Student{name='张三', age=23}=北京,
// Student{name='王五', age=23}=深圳,
// Student{name='张三', age=23}=上海,
// Student{name='李四', age=23}=广州}
//有重复键,需要在student重写hashcode和equals
//重写之后打印结果为
//{Student{name='张三', age=23}=上海,
// Student{name='王五', age=23}=深圳,
// Student{name='李四', age=23}=广州}
}
}
18.06_集合框架(LinkedHashMap的概述和使用)
- A:案例演示
- LinkedHashMap的特点
- 底层是链表实现的可以保证怎么存就怎么取
import java.util.LinkedHashMap;
public class Main {
public static void main(String[] args) {
LinkedHashMap<String,Integer> lnm = new LinkedHashMap<>();
lnm.put("张三",23);
lnm.put("李四",24);
lnm.put("王五",25);
System.out.println(lnm);
//{张三=23, 李四=24, 王五=25}
}
}
18.07_集合框架(TreeMap集合键是Student值是String的案例)
- A:案例演示
- TreeMap集合键是Student值是String的案例
- 案例一
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
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);
//报错 ClassCastException 没有实现compare接口不能比较
//student要实现compare接口
//{Student{name='张三', age=23}=北京,
// Student{name='李四', age=24}=上海,
// Student{name='王五', age=25}=广州,
// Student{name='赵六', age=26}=深圳}
}
}
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(){
super();
}
public Student(String name,int age){
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public int compareTo(Student o){
int num = this.age - o.age;//以年龄为主要条件
return num == 0 ? this.name.compareTo(o.name) : num;
//以姓名为次要条件
}
}
- 案例二
import java.util.Comparator;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
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);
//{Student{name='张三', age=23}=北京,
// Student{name='李四', age=24}=上海,
// Student{name='王五', age=25}=广州,
// Student{name='赵六', age=26}=深圳} 已排序
}
}
18.08_集合框架(统计字符串中每个字符出现的次数)
- A:案例演示
- 需求:统计字符串中每个字符出现的次数
import java.util.HashMap;
public class Main {
/**
* 需求:统计字符串中每个字符出现的次数
* 1.定义一个需要被统计字符的字符串
* 2.将字符串转换为字符数组
* 3.定义双列集合,存储字符串中字符以及字符出现的次数
* 4.遍历字符数组获取每一个字符,并将字符存储在双列集合中
* 5.存储过程中要做判断,如果集合中不包含这个键,就将该字符当做键,值为1存储
* 6.如果集合中不包含这个键,就降值加1存储
* 7.打印双列集合获取字符出现的次数
* @param args
*/
public static void main(String[] args) {
String str = "adcaacddca";
char[] arr = str.toCharArray();
HashMap<Character,Integer> hm = new HashMap<>();
//HashMap效率最高
for(char c : arr){
/*if(!hm.containsKey(c)){
hm.put(c,1);
}else{
hm.put(c,hm.get(c)+1);
}*/
hm.put(c, !hm.containsKey(c) ? 1 : hm.get(c) + 1);
}
for(Character key : hm.keySet()){
System.out.print(key+"="+hm.get(key)+" ");
//a=4 c=3 d=3
}
}
}
18.09_集合框架(集合嵌套之HashMap嵌套HashMap)
- A:案例演示
- 集合嵌套之HashMap嵌套HashMap
import java.util.HashMap;
public class Main {
/**
* 需求:HashMap嵌套HashMap
* 88期基础班定义成一个双列集合,键是学生对象,值是学生归属地
* 99期基础班定义成一个双列集合,键是学生对象,值是学生归属地
* 为了便于统一管理,把这些班级对象添加到课堂集合中
* @param args
*/
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("小明",17), "北京");
hm99.put(new Student("小华",18), "北京");
hm99.put(new Student("小红",19), "上海");
hm99.put(new Student("小花",16), "广州");
HashMap<HashMap<Student,String>,String> hm = new HashMap<>();
hm.put(hm88,"第88期基础班");
hm.put(hm99,"第99期基础班");
//遍历双列集合
for(HashMap<Student,String> h : hm.keySet()){ //hm.keySet()代表的是双列集合中键的集合
String value = hm.get(h); //get(h)根据键对象获取值对象
for(Student key : h.keySet()){ //h.keySet()获取集合中所有的学生键对象
String value2 = h.get(key);
System.out.println(key+" "+value2+" "+value);
// Student{name='张三', age=23} 北京 第88期基础班
// Student{name='李四', age=24} 北京 第88期基础班
// Student{name='王五', age=25} 上海 第88期基础班
// Student{name='赵六', age=26} 广州 第88期基础班
// Student{name='小明', age=17} 北京 第99期基础班
// Student{name='小花', age=16} 广州 第99期基础班
// Student{name='小华', age=18} 北京 第99期基础班
// Student{name='小红', age=19} 上海 第99期基础班
}
}
}
}
18.10_集合框架(HashMap和Hashtable的区别)
- A:面试题
- HashMap和Hashtable的共同点
- 底层都是哈希算法,都是双列集合
- HashMap和Hashtable的区别
- Hashtable是JDK1.0版本出现的,是线程安全的
- 效率低,HashMap是JDK1.2版本出现的,是线程不安全的,效率高
- Hashtable不可以存储null键和null值
- HashMap可以存储null键和null值
18.11_集合框架(Collections工具类的概述和常见方法讲解)
- A:Collections类概述
- 针对集合操作 的工具类
- B: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.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("d");
list.add("b");
Collections.sort(list);
System.out.println(list);//[a, b, c, d] 排序
ArrayList<String> list1 = new ArrayList<>();
list1.add("a");
list1.add("c");
list1.add("d");
list1.add("f");
System.out.println(Collections.binarySearch(list1,"d"));//2 二分查找
ArrayList<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("c");
list2.add("d");
list2.add("g");
System.out.println(Collections.max(list2));//g 找最大值
Collections.reverse(list2);
System.out.println(list2);//[g, d, c, a] 反转集合
Collections.shuffle(list2);
System.out.println(list2);//[d, g, a, c] 随机置换可用于洗牌
}
}
18.12_集合框架(模拟斗地主洗牌和发牌)
- A:案例演示
- 模拟斗地主洗牌和发牌,牌没有排序
import java.util.ArrayList;
import java.util.Collections;
public class Main {
/**
* 模拟斗地主洗牌和发牌
* 1.创建集合对象,将扑克牌存进去
* 2.洗牌,调用Collections的shuffle方法
* 3.发牌
* 4.看牌
* @param args
*/
public static void main(String[] args) {
String[] num = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
String[] color = {"红桃","黑桃","梅花","方块"};
ArrayList<String> poker = new ArrayList<>();
//拼接字符串,拼接花色和数字
for(String s1 : color){
for(String s2 : num){
poker.add(s1.concat(s2));//contact连接两个字符串
}
}
poker.add("小王");
poker.add("大王");
//洗牌
Collections.shuffle(poker);
//发牌
ArrayList<String> gaojin = new ArrayList<>();
ArrayList<String> longwu = new ArrayList<>();
ArrayList<String> me = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();//留三张给底牌
for(int i = 0; i < poker.size(); i++){
if(i >= poker.size() - 3){
dipai.add(poker.get(i));//将三张底牌存储在底牌集合中
}else if(i % 3 == 0){
gaojin.add(poker.get(i));
}else if(i % 3 == 1){
longwu.add(poker.get(i));
}else{
me.add(poker.get(i));
}
}
//看牌
System.out.println(gaojin);
System.out.println(longwu);
System.out.println(me);
System.out.println(dipai);
}
}
18.13_集合框架(模拟斗地主洗牌和发牌并对牌进行排序的原理图解)
- A:画图演示
- 画图说明排序原理
18.14_集合框架(模拟斗地主洗牌和发牌并对牌进行排序的代码实现)
- A:案例演示
- 模拟斗地主洗牌和发牌并对牌进行排序的代码实现
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
public class Main {
/**
* 模拟斗地主洗牌和发牌
* 1.创建集合对象,将扑克牌存进去
* 2.洗牌,调用Collections的shuffle方法
* 3.发牌
* 4.看牌
* @param args
*/
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;
//拼接扑克牌将索引和扑克牌存储在hm中
for(String s1 : num){ //获取数字
for(String s2 : color){ //获取颜色
hm.put(index, s2.concat(s1));//contact连接两个字符串
list.add(index); //将0-51索引添加到集合中
index++;
}
}
hm.put(index,"小王");
list.add(index); //将52索引添加到集合中
index++;
hm.put(index,"大王");
list.add(index); //将53索引添加到集合中
//洗牌
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,"底牌");
}
/**
* 1.返回类型void
* 2.参数列表HashMap,TreeSet,String name
*/
public static void lookPoker(HashMap<Integer,String> hm,TreeSet<Integer> ts,String name){
System.out.print(name+"的牌是:");
for(Integer i : ts){
System.out.print(hm.get(i)+" ");
}
System.out.println();
}
}
18.15_集合框架(泛型固定下边界)
- ? super 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 {
/**
* 泛型固定下边界
* ? super E
*
* 泛型固定上边界
* ? extends E
*/
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(ts2);
}
public static void demo1() {
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);
}
}
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;
}
}
18.16_集合框架(总结)
- A:Collection
- List ( 存取有序,有索引,可以重复)
- ArrayList:底层是数组实现的,线程不安全,查找修改快,增删慢
- LinkedList:底层是链表实现的,线程不安全,查找修改慢,增删快
- Vector:底层是数组实现的,线程安全,增删改查都慢
- 如果查找和修改多用ArrayList,如果增删多用LinkedList,如果都多用ArrayList
- Set(存取无序,无索引,不可以重复)
- HashSet:底层是哈希算法实现
- LinkedHashSet:底层是链表实现但是也可保证元素唯一,和HashSet一样
- TreeSet:底层是二叉树算法实现
- 一般在开发的时候不需要对存储的元素排序,所以在开发的时候大多用HashSet,HashSet效率比较高
- TreeSet在面试的时候问的比较多,问你有几种排序方式,和几种排序方式的区别
- B:Map
- HashMap:底层是哈希算法,针对键
- LinkedHashMap:底层是链表,针对键
- TreeMap:底层是二叉树算法,针对键
- 开发者HashMap用的比较多