目录
1 Map 集合
1.1 Map 集合概述
- 使用最多的
Map
集合是HashMap
- 重点掌握
HashMap
、LinkedHashMap
、HashTable
、TreeMap
单列集合一次存一个元素,双列集合一次存两个元素,一个键(不可以重复)对应一个值(可以重复)。(键+值)这个整体我们称之为键值对
或键值对对象
,在Java中叫做Entry对象
Map
是一种双列集合,也称为 键值对集合,其键无序、不重复,其值不做要求,可以重复,Map
集合的特点都是由键决定的,后面重复的键对应的值会覆盖前面重复键的值。其键值都可以为 null
HashMap
:元素按照键是无序、不重复、无索引、值不做要求(与Map
体系一致)LinkedHashMap
:元素按照键是 有序、不重复、无索引、值不做要求TreeMap
:元素按照键是 排序、不重复、无索引、值不做要求
Map 集合格式:
interface Map<K,V> // K:键的类型;V:值的类型
Map
集合是一个接口,不能直接创建对象,创建 Map
集合的对象有两种方式:
- 多态
- 具体的实现类 HashMap
基本用法:
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//map.add();
map.put("itheima001","小智");
map.put("itheima002","小美");
map.put("itheima003","大胖");
System.out.println(map);
}
1.2 Map 常用方法
Map
是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。
🙋举个栗子:
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("001","小智");
map.put("002","小美");
map.put("003","大胖");
map.put("004","小黑");
map.put("005","大师");
// 拓展,合并其他Map集合
Map<String,String> map2 = new HashMap<>();
map2.put("111","hu");
map2.put("222","long");
// 把map2的元素拷贝到map1中
map.putAll(map2);
//method1(map);
//method2(map);
//method3(map);
//method4(map);
//method5(map);
//method6(map);
//method7(map);
}
private static void method7(Map<String, String> map) {
// int size() 集合的长度,也就是集合中键值对的个数
int size = map.size();
System.out.println(size);
}
private static void method6(Map<String, String> map) {
// boolean isEmpty() 判断集合是否为空
boolean empty1 = map.isEmpty();
System.out.println(empty1);//false
map.clear();
boolean empty2 = map.isEmpty();
System.out.println(empty2);//true
}
private static void method5(Map<String, String> map) {
// boolean containsValue(Object value) 判断集合是否包含指定的值
boolean result1 = map.containsValue("aaa");
boolean result2 = map.containsValue("小智");
System.out.println(result1);
System.out.println(result2);
}
private static void method4(Map<String, String> map) {
// boolean containsKey(Object key) 判断集合是否包含指定的键
boolean result1 = map.containsKey("001");
boolean result2 = map.containsKey("006");
System.out.println(result1);
System.out.println(result2);
}
private static void method3(Map<String, String> map) {
// void clear() 移除所有的键值对元素
map.clear();
System.out.println(map);
}
private static void method2(Map<String, String> map) {
// V remove(Object key) 根据键删除键值对元素
String s = map.remove("itheima001");
System.out.println(s);
System.out.println(map);
}
private static void method1(Map<String, String> map) {
// V put(K key,V value) 添加元素
//如果要添加的键不存在,那么会把键值对都添加到集合中
//如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
String s = map.put("001", "aaa");
System.out.println(s);
System.out.println(map);
}
}
1.3 Map 的遍历
❗️注意:
- 使用
get
根据键获取值,当键不存在的时候会返回null
1️⃣ 遍历方式1:键找值
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();
//遍历Set集合得到每一个键
for (String key : keys) {
//通过每一个键key,来获取到对应的值
String value = map.get(key);
System.out.println(key + "---" + value);
}
}
2️⃣ 遍历方式2:键值对
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对象)
//而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);
}
}
3️⃣ 遍历方式3:lambda
表达式
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号妻子");
map.forEach(
(k,v)->{
System.out.println(k+"======>"+v);
}
);
}
2 HashMap 类
HashMap 类
HashMap
底层是哈希表结构的,与HashSet
底层原理是一样的,只是HashMap
的每个元素包含两个值而已- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
- 依赖
hashCode
方法和equals
方法保证 键 的唯一- 如果 键 要存储的是自定义对象,需要重写
hashCode
和equals
方法(hashCode
不同时,则必为不同对象;hashCode
相同时,根据equlas
方法不能判断是否为同一对象)
- 如果 键 要存储的是自定义对象,需要重写
实际上,
Set
系列集合的底层就是Map
实现的,只是Set
集合的数据只要键数据,不要值数据而已
🙋举个栗子:
案例需求:
- 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。
- 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
学生类
public 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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test {
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);
Student s4 = new Student("xiaomei", 22);
hm.put(s1, "江苏");
hm.put(s2, "北京");
hm.put(s3, "天津");
hm.put(s4, "天津");
//第一种:先获取到所有的键,再通过每一个键来找对应的值
Set<Student> keys = hm.keySet();
for (Student key : keys) {
String value = hm.get(key);
System.out.println(key + "----" + value);
}
System.out.println("===================================");
//第二种:先获取到所有的键值对对象。再获取到里面的每一个键和每一个值
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 + "----" + value);
}
System.out.println("===================================");
//第三种:
hm.forEach( //forEach方法在Map接口的两个实现类中都是可以实现的
(Student key, String value) -> {
System.out.println(key + "----" + value);
}
);
}
}
3 LinkedHashMap 类
LinkedHashMap
类
- 由键决定:有序、不重复、无索引
- 这里的有序指的是保证存储和取出的元素顺序一致
- 底层原理依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序
🙋举个栗子:
import java.util.LinkedHashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String,Integer> map=new LinkedHashMap<>();
map.put("哈哈",1);
map.put("嘿嘿",1);
map.put("嘻嘻",3);
map.put("呵呵",2);
map.put(null,null);
System.out.println(map); // {哈哈=1, 嘿嘿=1, 嘻嘻=3, 呵呵=2, null=null}
}
}
4 TreeMap 类
TreeMap
底层是红黑树结构- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
TreeMap
也是一定要排序的,依赖自然排序或者比较器排序,对 键 进行排序- 如果 键 存储的是自定义对象,需要实现
Comparable
接口或者在创建TreeMap
对象时候给出比较器排序规则 - 由于
TreeMap
元素不能重复,排序的时候只要大小一样,就认为重复,后面的重复数据会覆盖前面的
- 如果 键 存储的是自定义对象,需要实现
🙋举个栗子:
- 案例需求
- 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
- 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
- 代码实现
1️⃣ 实现Comparable
接口
学生类
public 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 result = o.getAge() - this.getAge(); // 从大到小排序,若是从小到大则需要为:int result = this.getAge()- o.getAge();
//次要条件,按照姓名排序。
result = result == 0 ? o.getName().compareTo(this.getName()) : result;
return result;
}
}
测试类
public static void main(String[] args) {
// 创建TreeMap集合对象
TreeMap<Student,String> tm = new TreeMap<>();
// 创建学生对象
Student s1 = new Student("xiaohei",23);
Student s2 = new Student("dapang",22);
Student s3 = new Student("xiaomei",22);
// 将学生对象添加到TreeMap集合中
tm.put(s1,"江苏");
tm.put(s2,"北京");
tm.put(s3,"天津");
// 遍历TreeMap集合,打印每个学生的信息
tm.forEach(
(Student key, String value)->{
System.out.println(key + "---" + value);
}
);
}
2️⃣ 创建TreeMap
对象时候给出比较器排序规则
学生类
public 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 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();
result = result== 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
Student s1 = new Student("xiaohei",23);
Student s2 = new Student("dapang",22);
Student s3 = new Student("xiaomei",22);
tm.put(s1,"江苏");
tm.put(s2,"北京");
tm.put(s3,"天津");
tm.forEach(
(Student key, String value)->{
System.out.println(key + "---" + value);
}
);
}
5 Properties
Properties
集合是一个Map体系的集合类,其属性列表中的每个键及其对应的值都是一个字符串。
创建
Properties
对象的时候不写泛型
5.1 Properties基本使用
public static void main(String[] args) {
Properties prop = new Properties();
//增
prop.put("小龙女","尹志平");
prop.put("郭襄","杨过");
prop.put("黄蓉","欧阳克");
System.out.println(prop);
//删
//prop.remove("郭襄");
//System.out.println(prop);
//改
//put --- 如果键不存在,那么就添加,如果键存在,那么就覆盖.
prop.put("小龙女","杨过");
System.out.println(prop);
//查
//Object value = prop.get("黄蓉");
//System.out.println(value);
//遍历
Set<Object> keys = prop.keySet();
for (Object key : keys) {
Object value = prop.get(key);
System.out.println(key + "=" + value);
}
System.out.println("========================");
//装的是所有的键值对对象.
Set<Map.Entry<Object, Object>> entries = prop.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(key + "=" + value);
}
}
5.2 Properties特有方法
public static void main(String[] args) {
//Object setProperty(String key, String value) --- put
//设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
Properties prop = new Properties();
prop.setProperty("江苏","南京");
prop.setProperty("安徽","南京");
prop.setProperty("山东","济南");
System.out.println(prop);
//String getProperty(String key) --- get
//使用此属性列表中指定的键搜索属性
String value = prop.getProperty("江苏");
System.out.println(value);
//Set<String> stringPropertyNames() --- keySet
//从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
String value = prop.getProperty(key);
System.out.println(key + "=" + value);
}
}
6 可变参数与不可变集合
6.1 可变参数
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
可变参数的作用:传输参数非常灵活、方便
- 可以不传输参数
- 可以传1个或多个参数
- 可以传输一个数组
当方法的参数类型已经确定,个数不确定,我们可以使用可变参数
可变参数定义格式
修饰符 返回值类型 方法名(数据类型… 变量名) { }
🙋举个栗子:
需求:定义一个方法求N个数的和
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
sum();
sum(10);
sum(10, 20);
sum(new int[]{1, 2, 3, 4, 5});
/* 元素个数:0
元素内容:[]
元素个数:1
元素内容:[10]
元素个数:2
元素内容:[10, 20]
元素个数:5
元素内容:[1, 2, 3, 4, 5]*/
}
public static void sum(int... nums) {
// 可变参数本质上就是一个数组
System.out.println("元素个数:"+nums.length);
System.out.println("元素内容:"+ Arrays.toString(nums));
}
}
❗️注意:
- 可变参数在方法内部本质上就是一个数组
- 一个形参列表中可变参数只有一个
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
6.2 不可变集合
不可变集合,即不可以被修改的集合,集合的数据项在创建的时候提供,并且在整个生命周期中都不改变,否则报错
为什么要创建不可变集合?
- 如果某个数据不能被修改,把它防御性地拷贝到不可变集合红是个很好的实践
- 或者当集合对象被不可信的库调用时,不可变形式是安全的
如何创建不可变集合?
- 在
List
、Set
、Map
接口中,都存在of
方法,可以创建一个不可变的集合- 这个集合不能添加,不能删除,不能修改
- 但是可以结合集合的带参构造,实现集合的批量添加
- 在
Map
接口中,还有一个ofEntries
方法可以提高代码的阅读性- 首先会把键值对封装成一个
Entry
对象,再把这个Entry
对象添加到集合当中
- 首先会把键值对封装成一个
🙋举个栗子:
public static void main(String[] args) {
// static <E> List<E> of(E…elements) 创建一个具有指定元素的List集合对象
//static <E> Set<E> of(E…elements) 创建一个具有指定元素的Set集合对象
//static <K , V> Map<K,V> of(E…elements) 创建一个具有指定元素的Map集合对象
//method1();
//method2();
//method3();
//method4();
}
private static void method4() {
Map<String, String> map = Map.ofEntries(
Map.entry("zhangsan", "江苏"),
Map.entry("lisi", "北京"));
System.out.println(map); // {lisi=北京, zhangsan=江苏}
}
private static void method3() {
Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津");
System.out.println(map); // {lisi=北京, zhangsan=江苏, wangwu=天津}
}
private static void method2() {
//传递的参数当中,不能存在重复的元素。
Set<String> set = Set.of("a", "b", "c", "d","a");
System.out.println(set); // 会报错
}
private static void method1() {
List<String> list = List.of("a", "b", "c", "d");
System.out.println(list); // [a, b, c, d]
//集合的批量添加。
//首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
//再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
ArrayList<String> list3 = new ArrayList<>(List.of("a", "b", "c", "d"));
System.out.println(list3);
}
7 集合工具类Collections
java.utils.Collections
:是集合工具类,Collections
并不属于集合,而是用来操作集合的工具类
💞 Collections
常用的 API
Collections
排序相关 API
- 使用范围:只能对于
List
集合的排序
示例代码:
学生类
public class Student {
private String names;
private int age;
private double height;
public Student() {
}
public Student(String names, int age, double height) {
this.names = names;
this.age = age;
this.height = height;
}
public String getNames() {
return names;
}
public void setNames(String names) {
this.names = names;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"names='" + names + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
测试类
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
// 一个一个添加元素
// names.add("高辛玖瑶");
// names.add("涂山璟");
// names.add("九命相柳");
// names.add("西炎玱玹");
// names.add("赤水丰隆");
// System.out.println(names);
// 批量添加元素
Collections.addAll(names, "高辛玖瑶", "涂山璟", "九命相柳", "西炎玱玹", "赤水丰隆");
System.out.println(names); // [高辛玖瑶, 涂山璟, 九命相柳, 西炎玱玹, 赤水丰隆]
// 打乱集合顺序
Collections.shuffle(names);
System.out.println(names); // [涂山璟, 高辛玖瑶, 赤水丰隆, 九命相柳, 西炎玱玹]
// 将集合中的元素按照默认规则排序(排值特性的元素)
List<Integer> nums = new ArrayList<>();
Collections.addAll(nums, 10, 5, 6, 8, 4, 1);
Collections.sort(nums);
System.out.println(nums); // [1, 4, 5, 6, 8, 10]
// 对自定义对象排序(也可以在自定义对象类中重写比较规则)
List<Student> stus = new ArrayList<>();
stus.add(new Student("小胖",20,173.1));
stus.add(new Student("小美",18,159.9));
stus.add(new Student("小黑",21,183.5));
Collections.sort(stus, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// return o1.getAge()- o2.getAge(); // 按年龄升序排序
return Double.compare(o1.getHeight(),o2.getHeight()); // 按身高升序排序
}
});
System.out.println(stus);
}
}