1.Map集合
单列集合一次只能存入一个数据,而双列集合一次可以存入两个(一对)数据
(键key,值value) : 称为”键值对“或”键值对对象“、java中叫"Entry"对象
1.1Map集合概述和特点【理解】
-
Map集合概述
interface Map<K,V> K:键的类型;V:值的类型
-
Map集合的特点
双列集合,一个键对应一个值
键不可以重复,值可以重复
- Map集合的基本使用
public static void main(String[] args) {
//<学号,姓名>
Map<String,String > map=new HashMap<>();
//新的collection分支的公共方法了
//没有add,插入双列值得put
map.put("whu1001","小米");
map.put("whu1002","小美");
map.put("whu1003","大胖");
map.put("whu1002","小美1");//key重复的会被舍弃 保留最后一个
System.out.println(map);//"{whu1002=小美1, whu1001=小米, whu1003=大胖}"
}
1.2Map集合的基本功能【应用】 (★所有map共有的一些方法★)
Map接口里的方法,HashMap和TreeMap都会有的
-
方法介绍
方法名 说明 V put(K key,V value) 添加元素 V remove(Object key) 根据键删除键值对元素 void clear() 移除所有的键值对元素 boolean containsKey(Object key) 判断集合是否包含指定的键 boolean containsValue(Object value) 判断集合是否包含指定的值 boolean isEmpty() 判断集合是否为空 int size() 集合的长度,也就是集合中键值对的个数 -
示例代码1: V put(K key,V value)
//如果要添加的键不存在,那么会把键值对都添加到集合中
//如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
public static void main(String[] args) {
Map<String,String > map=new HashMap<>();
// V put(K key,V value) | 添加元素
//如果要添加的键不存在,那么会把键值对都添加到集合中
//如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
map.put("whu1001","小米");
map.put("whu1002","小美");
map.put("whu1003","大胖");
map.put("whu1004","小黑");
map.put("whu1005","大帅1");
String s = map.put("whu1005", "大帅");//返回已经存在key对应的value
System.out.println(s);//"大帅1"
System.out.println(map);
//输出: {whu1002=小美, whu1001=小米, whu1004=小黑, whu1003=大胖, whu1005=大帅}
//无序 key不重复 键值对形式
}
- 示例代码2: V remove(Object key)
public static void main(String[] args) {
Map<String,String > map=new HashMap<>();
map.put("whu1001","小米");
map.put("whu1002","小美");
map.put("whu1003","大胖");
map.put("whu1004","小黑");
map.put("whu1005","大帅");
// V remove(Object key) | 根据键删除键值对元素
String s = map.remove("whu1001");
System.out.println(s);//"小米"
//小米被删除了
System.out.println(map);//"{whu1002=小美, whu1004=小黑, whu1003=大胖, whu1005=大帅}"
}
- 示例代码3: void clear()
public static void main(String[] args) {
Map<String,String > map=new HashMap<>();
map.put("whu1001","小米");
map.put("whu1002","小美");
map.put("whu1003","大胖");
map.put("whu1004","小黑");
map.put("whu1005","大帅");
// void clear() | 移除所有的键值对元素
map.clear();//真的清空了所有键值对
System.out.println(map);//"{}"
}
- 示例代码4: boolean containsKey(Object key) && boolean containsValue(Object value)
public static void main(String[] args) {
Map<String,String > map=new HashMap<>();
map.put("whu1001","小米");
map.put("whu1002","小美");
map.put("whu1003","大胖");
map.put("whu1004","小黑");
map.put("whu1005","大帅");
// boolean containsKey(Object key) | 判断集合是否包含指定的键
boolean b1 = map.containsKey("whu1001");
boolean b2 = map.containsKey("whu1007");
System.out.println(b1);//true
System.out.println(b2);//false
// boolean containsValue(Object value) | 判断集合是否包含指定的值
boolean res1 = map.containsValue("小米");
boolean res2 = map.containsValue("大米");
System.out.println(res1);//true
System.out.println(res2);//false
}
- 示例代码5: int size() && boolean isEmpty()
public static void main(String[] args) {
Map<String,String > map=new HashMap<>();
map.put("whu1001","小米");
map.put("whu1002","小美");
map.put("whu1003","大胖");
map.put("whu1004","小黑");
map.put("whu1005","大帅");
// int size() | 集合的长度,也就是集合中键值对的个数
int size = map.size();
System.out.println(size);//5
// boolean isEmpty() | 判断集合是否为空
boolean b = map.isEmpty();
System.out.println(b);//false
map.clear();
System.out.println(map.isEmpty());//true
System.out.println(map.size());//0
}
1.3Map集合的获取功能【应用】(还是顶层接口,也就是所有map都有的方法)
-
方法介绍
方法名 说明 V get(Object key) 根据键获取值 Set keySet() 获取所有键的集合 Collection values() 获取所有值的集合 Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合
简单查下API,就能知道Map.Entry的所有方法
- 示例代码
public static void main(String[] args) {
//创建集合 并添加元素
Map<String,String> map=new HashMap<>();
map.put("1号丈夫","1号妻子");
map.put("2号丈夫","2号妻子");
map.put("3号丈夫","3号妻子");
map.put("4号丈夫","4号妻子");
map.put("5号丈夫","5号妻子");
System.out.println("=============所有键==============");
//获取所有键
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key);
}
//获取所有值
System.out.println("=============所有值==============");
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
//获取所有键值对
System.out.println("==============所有键值对==============");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry);
//entry.getKey();//都有
//entry.getValue();//都有
}
}
1.4Map集合的遍历(方式1:遍历keySet,再一个一个获取值)【应用】
-
遍历思路
- 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
- 把所有的丈夫给集中起来
- 遍历丈夫的集合,获取到每一个丈夫
- 根据丈夫去找对应的妻子
- 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
-
步骤分析
- 获取所有键的集合。用keySet()方法实现
- 遍历键的集合,获取到每一个键。用增强for实现
- 根据键去找值。用get(Object key)方法实现
-
代码实现
public static void main(String[] args) {
//创建集合 并添加元素
Map<String,String> map=new HashMap<>();
map.put("1号丈夫","1号妻子");
map.put("2号丈夫","2号妻子");
map.put("3号丈夫","3号妻子");
map.put("4号丈夫","4号妻子");
map.put("5号丈夫","5号妻子");
//获取所有的键
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key+" "+map.get(key));
}
}
1.5Map集合的遍历(方式2:直接获取键值对集合entrySet())【应用】
-
遍历思路
- 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
- 获取所有结婚证的集合
- 遍历结婚证的集合,得到每一个结婚证
- 根据结婚证获取丈夫和妻子
- 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
-
步骤分析
- 获取所有键值对对象的集合(Map的内部接口 因此写为Map.Entry)
- Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
- 遍历键值对对象的集合,得到每一个键值对对象
- 用增强for实现,得到每一个Map.Entry
- 根据键值对对象获取键和值
- 用getKey()得到键
- 用getValue()得到值
- 获取所有键值对对象的集合(Map的内部接口 因此写为Map.Entry)
-
代码实现
public static void main(String[] args) {
//创建集合 并添加元素
Map<String,String> map=new HashMap<>();
map.put("1号丈夫","1号妻子");
map.put("2号丈夫","2号妻子");
map.put("3号丈夫","3号妻子");
map.put("4号丈夫","4号妻子");
map.put("5号丈夫","5号妻子");
//注意此处有两个泛型嵌套
//Set集合的泛型是键值对对象(Entry对象),泛型就是Map.Entry(Entry是Map的内部接口)
//Entry里存储的键值对,其两个泛型分别是键类型、值类型
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"--"+value);
}
}
2.HashMap集合(底层哈希表)
Map的一个实现类 没有额外要学习的方法,直接使用Map里的方法就行了
底层也是哈希表
jdk8之前 数组+链表
jdk8以后 数组+链表|红黑树
(底层和HashSet一样 或者不如说HashSet直接底层就是用到HashMap )
2.1HashMap集合概述和特点【理解】
- HashMap底层是哈希表结构的
- 依赖hashCode方法和equals方法保证键的唯一
- 如果键要存储的是自定义对象,需要重写hashCode和equals方法
2.2HashMap集合应用案例【应用】
-
案例需求
- 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
- 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
-
代码实现
Student.java
public class Student {
private String name;
private Integer age;
// 空参构造
// 全参构造
// 所有get/set
//tostring
//重写(其实是自动生成) equals和hashCode方法 【HashSet和HashMap存储自定义对象时 必须的步骤】
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name) &&
Objects.equals(age, student.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
测试
public static void main(String[] args) {
//<学生,籍贯>
HashMap<Student,String> hm=new HashMap<>();
Student s1 = new Student("xiaohei", 23);
Student s2 = new Student("dapang", 22);
Student s3 = new Student("xiaomei", 22);
hm.put(s1,"苏");
hm.put(s2,"京");
hm.put(s3,"津");
//三种方式遍历
//1.先获取所有键keySet() 再遍历
Set<Student> keys = hm.keySet();
for (Student key : keys) {
String s = hm.get(key);
System.out.println(key+"\t"+s);
}
System.out.println("==================================");
//2.直接获取所有键值对
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"\t"+value);
}
System.out.println("==================================");
//3.Map.forEach(lambda表达式) ★
//参数(键,值) 方法体:想干啥 直接写
hm.forEach((Student key,String value)->{System.out.println(key+"\t"+value);});
}
新增一种遍历方式,forEach
查看源码,就是用for帮你遍历了
HashMap的
Map的
3.TreeMap集合(底层红黑树 自动排序 查找也飞快)
同样没有新方法要学习,直接用Map接口中的方法即可
3.1TreeMap集合概述和特点【理解】
- TreeMap底层是红黑树结构
- 依赖自然排序或者比较器排序,对键进行排序
- 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
每个键值对打包在一起作为一个结点 但是比较大小时只关心键,不关心值
每次put都在构建(插入)红黑树
3.2TreeMap集合应用案例一【应用】
-
案例需求
- 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
- 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
-
代码实现1
学生类
public class Student implements Comparable<Student>{
//用到了Tree 红黑树 必须给出compareTo比较规则 否则遍历就会报错
private String name;
private Integer age;
// 空参构造
// 全参构造
// 所有get/set
// tostring
//用到了Tree 红黑树 必须给出compareTo比较规则 否则遍历就会报错
@Override
public int compareTo(Student o) {
//一级排序年龄升序 二级排序姓名序
int result = this.getAge() - o.getAge();
if(result==0) result=this.getName().compareTo(o.getName());
return result;
}
}
Test1.java
public class Test1 {
public static void main(String[] args) {
TreeMap<Student,String> tm=new TreeMap<>();
Student s1 = new Student("xiaohei", 23);
Student s2 = new Student("dapang", 22);
Student s3 = new Student("xiaomei", 22);
Student s4 = new Student("tianhe", 19);
Student s5 = new Student("xiaomei", 22);//重复的自动不要
tm.put(s1,"苏");
tm.put(s2,"京");
tm.put(s3,"津");
tm.put(s4,"皖");
tm.put(s5,"浙");
//使用就很方便了 (主要时验证下 有没有根据年龄排序)
Set<Student> keys = tm.keySet();
for (Student key : keys) {
String s = tm.get(key);
System.out.println(key+"\t"+s);
}
}
}
- 代码实现2
student.java
public class Student implements Comparable<Student>{
//用到了Tree 红黑树 必须给出compareTo比较规则 否则遍历就会报错
private String name;
private Integer age;
// 空参构造
// 全参构造
// 所有get/set
// tostring
}
Test2.java
public static void main(String[] args) {
TreeMap<Student,String> tm=new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int result= o1.getAge()-o2.getAge();
if(result==0) result=o1.getName().compareTo(o2.getName());
return -result;//加个负号变降序
}
});
Student s1 = new Student("xiaohei", 23);
Student s2 = new Student("dapang", 22);
Student s3 = new Student("xiaomei", 22);
Student s4 = new Student("tianhe", 19);
Student s5 = new Student("xiaomei", 22);//重复的自动不要
tm.put(s1,"苏");
tm.put(s2,"京");
tm.put(s3,"津");
tm.put(s4,"皖");
tm.put(s5,"浙");
//使用就很方便了 (主要时验证下 有没有根据年龄排序)
tm.forEach((Student key, String value)->{System.out.println(key+"\t"+value);});
}
3.3TreeMap集合应用案例二【应用】
-
案例需求
- 给定一个字符串,要求统计字符串中每个字符出现的次数。
- 举例: 给定字符串是“aababcabcdabcde”,在控制台输出: “a(5)b(4)c(3)d(2)e(1)”
看成普通Map就行了 map[‘a’]='a’出现次数 (其实是map.get(‘a’)=='a’出现次数)
用treeMap,自动按key排序了
- 代码实现
public static void main(String[] args) {
String s="aababcabcdabcde";
TreeMap<Character,Integer> tm=new TreeMap<>();
for(int i=0;i<s.length();i++){
Character c=s.charAt(i);
if(tm.containsKey(c)){
tm.put(c,tm.get(c)+1);//次数+1 直接重复复制就会覆盖(插入没有HashMap快)
}else {
tm.put(c,1);
}
}
tm.forEach((Character key,Integer value)->{System.out.print(key+" ("+value+") ");});
}
4.可变参数
4.1可变参数【应用】
-
可变参数介绍
- 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
- 方法的参数类型已经确定,个数不确定,我们可以使用可变参数
-
可变参数定义格式
修饰符 返回值类型 方法名(数据类型… 变量名) { }
例如:
int sum(int... a) {}
-
可变参数的注意事项
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后(轮到可变参数接收时,给多少要多少,只能放在最后)
-
可变参数的基本使用
定义一个方法,求N个整数的和
jdk5之前
/**
* 定义一个方法,求N个数的和
*/
public class MyVariableParameter2 {
public static void main(String[] args) {
//jdk5之前 自己用数组实现
int[] arr={1,2,3,4,5};//还得提起申请数组,好麻烦
int sum1=getSum(arr);
System.out.println(sum1);//15
}
private static int getSum(int[] arr) {
int sum=0;
for (int i : arr) sum+=i;
return sum;
}
}
jdk5之后
/**
* 定义一个方法,求N个数的和
*/
public class MyVariableParameter2 {
public static void main(String[] args) {
//jdk5之后直接用可变参数即可 ★
int sum2=getSum2(1,2,3,4,5);//可以直接写任意多个参数
System.out.println(sum2);//15
System.out.println(getSum2(7,8,9,10));//34
}
private static int getSum2(int... arr) {
int sum=0;
for (int i : arr) sum+=i;
return sum;
}
}
4.2创建不可变集合【理解】(JDK9引入)
-
方法介绍
- 在List、Set、Map接口中,都存在of方法(形参都是可变参数),可以创建一个不可变的集合
- 这个集合不能添加,不能删除,不能修改
- 但是可以结合集合的带参构造,实现集合的批量添加
- 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
- 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
- 在List、Set、Map接口中,都存在of方法(形参都是可变参数),可以创建一个不可变的集合
- 示例代码1:List.of(…)
static List of(E…elements) 创建一个具有指定元素的List集合对象
public static void main(String[] args) {
// static <E> List<E> of(E…elements) 创建一个具有指定元素的List集合对象
//jdk9引入的新方法 jdk8以及8以下都执行不了
List<String> list=List.of("a","b","c","d");
System.out.println(list);//输出: [a,b,c,d]
//list.add("Q");//报错: 不准添加
//list.remove("a");//报错: 不准删除
//list.set(0,"A");//报错: 不准修改
System.out.println(list);
//使用: 集合的批量添加。
//首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
//再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。(其实是利用了List的有参构造)
ArrayList<String> list3=new ArrayList<>(List.of("a","b","c","d"));
//初始化时不需要慢慢调用list.add("XX")方法了 多方便
System.out.println(list3);//输出: [a,b,c,d]
}
- 示例代码2:Set.of(…)
static Set of(E…elements) 创建一个具有指定元素的Set集合对象
public static void main(String[] args) {
//static <E> Set<E> of(E…elements) 创建一个具有指定元素的Set集合对象
//传递的参数当中,不能存在重复的元素。
Set<String> set = Set.of("a", "b", "c", "d");
//Set<String> set = Set.of("a", "b", "c", "d","a");//报错 不能有重复
System.out.println(set);//输出: [a,b,c,d]
}
- 示例代码3:Map.of(…)
static <K , V> Map<K,V> of(E…elements) 创建一个具有指定元素的Map集合对象
public static void main(String[] args) {
//static <K , V> Map<K,V> of(E…elements)
// 创建一个具有指定元素的Map集合对象
Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津");
System.out.println(map);//输出: {lisi=北京, wangwu=天津, zhangsan=江苏}
}
Map.ofEntries( Map.entry(“zhangsan”, “江苏”), Map.entry(“lisi”, “北京”));
Map<String, String> map = Map.ofEntries(//同样jdk9才有
Map.entry("zhangsan", "江苏"),
Map.entry("lisi", "北京"));//先封装两个entry对象,再将entry对象放到map中
System.out.println(map);