Java常用工具-集合
1. 集合简介
什么是集合?
简称集,是用来存储多个元素的容器
集合和数组的区别
- 元素类型
集合:引用类型(存储基本类型时自动装箱)
数组:基本类型、引用类型 - 元素个数
集合:不固定,可任意扩容
数组:固定,不能改变容量 - 集合的好处
不受容器大小限制,可以随时添加、删除元素
提过了大量操作元素的方法(判断、获取等)
Java的集合体系
2. List集合的特点和应用
List集合的特点
案例:List集合的简单使用
代码演示
//学生类
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 +
'}';
}
}
import java.util.ArrayList;
import java.util.List;
/*
使用集合的步骤:
1. 创建集合对象
2. 创建元素对象
3. 将元素对象添加到集合对象中
4. 遍历集合
*/
public class Test {
public static void main(String[] args) {
//需求:往List集合中添加3个学生对象,然后遍历
//1. 创建集合对象
List list = new ArrayList();
//2. 创建元素对象
Student s1 = new Student("张三",41);
Student s2 = new Student("张三",41);
Student s3 = new Student("李四",42);
Student s4 = new Student("王五",43);
//3. 将元素对象添加到集合对象中
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
//直接打印集合
System.out.println(list);
//获取索引为2的元素
Object obj = list.get(2);
System.out.println("索引为2的元素是:" + obj);
//获取结合中元素个数
System.out.println("集合的长度为:" + list.size());
//4. 遍历集合
for (int i = 0; i < list.size(); i++) {
//i表示的就是集合中每个元素的索引
//获取元素
Object obj2 = list.get(i);
System.out.println("索引为:" + i + "的元素是:" + obj2);
}
}
}
运行结果
3. 增强for循环和迭代器
为什么需要增强for循环?
简化数组和集合的遍历
- 增强for循环的格式:
for(数据类型 变量名 : 数组或者集合对象) {
//循环体,变量即元素
}
代码演示
import java.util.ArrayList;
import java.util.List;
/*
快捷方式 iter + enter
注意:
增强for的底层依赖的是迭代器(Iterator)
大白话解释:增强for就是迭代器的间歇形式
*/
public class Test {
public static void main(String[] args) {
//需求:通过增强for遍历List集合
//1. 创建集合对象
List list = new ArrayList();
//2. 创建元素对象
//3. 将元素对象添加到集合中
list.add(10);
list.add(10);
list.add(30);
list.add(20);
list.add(40);
//4. 遍历集合
for (Object obj : list) {
//obj是集合中的元素,其本身应该是Integer类型的数据
Integer i1 = (Integer)obj;
System.out.println(i1);
}
System.out.println("-----------------");
for (Object obj : list) {
Integer i1 = (Integer)obj;
System.out.println(i1);
}
}
}
运行结果
为什么需要迭代器?
对过程的重复,称为迭代。
迭代器是变量Collection集合的通用方式,可以在对集合遍历的同时进行添加、删除等操作。
迭代器的常用方法
- next():返回迭代的下一个元素对象
- hasNext():如果仍有元素可以迭代,则返回true
Demo1
代码演示
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
注意:
列表迭代器是List体系独有的遍历方式,可以在对集合遍历的同时进行添加、删除等操作
但是必须通过调用列表迭代器的方法来实现
使用步骤:
1. 根据集合对象获取其对象的迭代器对象。
2. 判断迭代器中是否有元素
3. 如果有就获取元素
总结:
普通的迭代器在遍历集合的同时不能添加或者删除元素,否则会报:并发修改异常
列表迭代器在遍历集合的同时可以修改集合中的元素(添加,删除等),必须使用列表迭代器中的方法
*/
public class Test {
public static void main(String[] args) {
//需求:通过迭代器遍历List集合
//1. 创建集合对象
List list = new ArrayList();
//2. 创建元素对象
//3. 将元素对象添加到集合当中
list.add("a");
list.add("b");
list.add("c");
//4. 遍历集合
//迭代器的用法
//1. 根据集合对象获取其对象的迭代器对象。
/*Iterator it = list.iterator();
//2. 判断迭代器中是否有元素
while (it.hasNext()) { //如果迭代器中有元素,就一直迭代
//3. 如果有就获取元素
String s = (String)it.next();
System.out.println(s);
}*/
System.out.println("---------------------");
//需求:判断集合中如果有字符串"b",就在其后边添加一个新的字符串:java
Iterator it = list.iterator();
//2. 判断迭代器中是否有元素
while (it.hasNext()) { //如果迭代器中有元素,就一直迭代
//3. 如果有就获取元素
String s = (String)it.next();
if ("b".equals(s)) { //这样写可以规避空指针异常,"b"是常量
//能走到这里,说明集合中有元素b
list.add("java"); //这样写不行,会报ConcurrentModificationException(并发修改异常)
}
System.out.println(s);
}
}
}
运行结果
Demo2
代码演示
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Test1 {
public static void main(String[] args) {
//需求:测试列表迭代器
//1. 创建集合对象
List list = new ArrayList();
//2. 创建元素对象
//3. 将元素对象添加到集合当中
list.add("a");
list.add("b");
list.add("c");
//需求:判断集合中如果有字符串"b",就在其后边添加一个新的字符串:java
//1. 根据集合对象获取列表迭代器对象
ListIterator lit = list.listIterator();
//2. 判断迭代器中是否有元素
while (lit.hasNext()) {
//3. 有就获取元素即可
String s = (String)lit.next();
if ("b".equals(s)) {
//list.add("java"); 这样写不行,必须调用列表迭代器的方法来实现.
lit.add("java");
}
System.out.println(s);
}
System.out.println("-------------");
//打印新的集合中的值
System.out.println(list);
}
}
运行结果
4. 泛型简介
什么是泛型?
即泛指任意类型,又叫参数化类型(ParameterizedType),
对具体类型的使用起到辅助作用,类似于方法的参数。
集合类泛型的解释
表示该集合中存放指定类型的元素
- 案例演示(给List集合加上泛型String)
List list = new ArrayList<>(); - 泛型的好处
类型安全
避免了类型转换
代码演示
import java.util.ArrayList;
import java.util.List;
/*
总结:
泛型一般只和集合类相结合使用
泛型JDK5的新特性,但从JDK7开始,后边的泛型可以不用写具体的数据类型了(菱形泛型)
*/
public class Test {
public static void main(String[] args) {
//不使用泛型的集合
//1. 创建集合对象
List list = new ArrayList();
//2. 创建元素对象
//3. 将元素对象添加到集合对象中
list.add("a");
list.add("b");
list.add("c");
//list.add(10); 会报类型转换异常(ClassCastException)
//4. 遍历集合
for (Object obj : list) {
String s = (String)obj;
System.out.println(s);
}
System.out.println("-----------------");
//需求:演示泛型
//1. 创建集合对象
List<String> list2 = new ArrayList<>();
//2. 创建元素对象
//3. 将元素对象添加到集合对象中
list2.add("abc");
list2.add("bcd");
list2.add("cde");
//4. 遍历集合
for (String s : list2) {
System.out.println(s);
}
}
}
运行结果
5. Collections工具类
Collections简介
针对集合进行操作的工具类
成员方法
代码演示
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
//创建集合对象
List<Integer> list = new ArrayList<>();
//往集合中添加数据
list.add(1);
list.add(3);
list.add(3);
list.add(5);
list.add(2);
list.add(2);
list.add(4);
//打印集合
System.out.println("没有操作以前,集合中的数据是:" + list);
System.out.println("-----------------");
//获取集合中最大元素
Integer max = Collections.max(list);
System.out.println("集合中的最大元素为:" + max);
System.out.println("-----------------");
//对集合进行升序排列
Collections.sort(list);
System.out.println("升序排列后的结果为:" + list);
System.out.println("-----------------");
//对集合中的数据进行反转
Collections.reverse(list);
System.out.println("反转以后集合中的数据为:" + list);
//需求:对集合中的数据进行降序排列
//先对集合中的数据进行:升序排列
Collections.sort(list);
//然后反转集合中的数据
Collections.reverse(list);
System.out.println("降序后的结果为:" + list);
System.out.println("-----------------");
//随机置换,相当于洗牌
Collections.shuffle(list);
System.out.println("随机置换后的结果为:" + list);
}
}
运行结果
6. Set集合的特点
Set集合的特点
- 特点
不可重复、无序 - 应用
Set <T> set = new HashSet<>();
案例:Set集合的简单使用
代码演示
import java.util.Objects;
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 +
'}';
}
@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.HashSet;
import java.util.Iterator;
import java.util.Set;
/*
结论:
Set集合保证元素的唯一性依赖:equals(),hashCode()两个方法。
*/
public class Test {
public static void main(String[] args) {
//需求:往set集合中添加5个学生对象,然后遍历
//1. 创建集合对象
Set<Student> set = new HashSet<>();
//2. 创建元素对象
Student s1 = new Student("张三", 41);
Student s2 = new Student("李四", 42);
Student s3 = new Student("王五", 43);
Student s4 = new Student("张三", 41);
Student s5 = new Student("李四", 42);
//3. 将集合对象添加到元素对象中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
//4. 遍历集合
/*
为什么Set集合没有“去重”?
因为Set集合宝恒元素的唯一性依赖:equals() 和 hashCode()两个方法
你没有在Student类中重写这两个方法,默认调用的是Object类中的这两个方法
而Object类中的equals()方法默认比较的是地址值是否相同
解决方案:
在Student类中重写equals()和hashCode()方法
*/
System.out.println(set);
System.out.println("-------------");
System.out.println("通过迭代器实现");
//通过迭代器遍历Set集合
//A. 通过集合对象获取其对应的迭代器对象
Iterator<Student> it = set.iterator();
//B. 判断迭代器中是否有元素
while (it.hasNext()) {
//C. 如果有,就获取元素
Student s = it.next();
System.out.println(s);
}
System.out.println("-------------");
//通过增强for遍历Set集合
System.out.println("通过增强for遍历Set集合");
for (Student student : set) {
System.out.println(student);
}
}
}
运行结果
7. Map集合的特点和应用
Map集合的特点
- 特点
双列集合,元素由键值对(Entry)构成:
key – value
key不可以重复,value可以重复 - 应用
Map<T1,T2> map = new HashMap<>();
案例:Map集合的简单使用
5.通过key分别获取对应的value并打印
代码演示
import java.util.Objects;
//学生类
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;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
遍历步骤:
1. 获取所有键的集合 keySet()
2.遍历所有的键,获取到每一个键, 迭代器,增强for
3. 根据键获取指定的值 get()
*/
public class Test {
public static void main(String[] args) {
//需求:往Map集合中添加3个学生对象,然后打印
//1. 创建集合对象
//键:学生的编号 值:具体的学生对象
Map<Integer,Student> map = new HashMap<>();
//2. 创建元素对象
Student s1 = new Student("张三",23);
Student s2 = new Student("李四",24);
Student s3 = new Student("张三",23);
//3. 将元素对象添加到集合对象中
//put() 元素第一次添加,返回null,重复添加,会用新值覆盖旧值,并返回旧值
/*Student stu1 = map.put(1,s1);
System.out.println("stu1:" + stu1);
Student stu2 = map.put(1,s2);
System.out.println("stu2:" + stu2);*/
map.put(1,s1);
map.put(2,s2);
map.put(3,s3);
//根据键,获取值
Student stu3 = map.get(2);
System.out.println("key:" + 2 + ",value:" + stu3);
//打印集合
System.out.println(map);
System.out.println("--------------------");
//4. 遍历集合
/*//4.1. 获取所有键的集合 keySet()
Set<Integer> keys = map.keySet();
//4.2.遍历所有的键,获取到每一个键, 迭代器,增强for
Iterator<Integer> it = keys.iterator();
while (it.hasNext()) {
//如果迭代中有数据,就获取
Integer key = it.next();
//4.3. 根据键获取指定的值 get()
Student value = map.get(key);
System.out.println("key:" + key + ",value:" + value);
}*/
//通过增强for实现
//获取到所有的键
Set<Integer> keys = map.keySet();
for (Integer key : keys) {
//key就是双列结合中的每一个键
Student value = map.get(key);
System.out.println("key:" + key + ",value:" + value);
}
}
}
运行结果
8. 案例:模拟斗地主发牌功能
import java.util.*;
public class SendPokerTest {
public static void main(String[] args) {
//1. 买牌
//1.1 定义一个双列集合,键:表示键的编号,值:表示具体的牌 规则:编号越小,牌越小
Map<Integer, String> pokers = new HashMap<>();
//1.2 定义一个单列集合,用来存储所有牌的编号
List<Integer> list = new ArrayList<>();
//1.3具体的买牌动作
//普通牌,52
String[] colors = {"♠","♥","♣","♦"};
String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
int num = 0;
//通过循环嵌套,造 普通牌
for (String number : numbers) { //外循环,获取所有的点数
for (String color : colors) { //内循环,获取所有的花色
String poker = color + number;
//System.out.println(poker);
//将牌的编号,具体的牌放到双列集合中
pokers.put(num, poker);
//将牌的编号放到单列集合中
list.add(num);
//每添加一张牌,编号要自增1
num++;
}
}
//大小王
//添加小王
pokers.put(num,"小王");
list.add(num++);
//添加大王
pokers.put(num,"大王");
list.add(num);
//打印牌
System.out.println("所有牌:" + pokers);
System.out.println("牌的编号" + list);
//2. 洗牌
Collections.shuffle(list);
System.out.println("洗好牌后,编号为:" + list);
//3. 发牌
//3.1 定义4个集合,分别表示3个玩家,底牌.
List<Integer> Jake = new ArrayList<>();
List<Integer> Jennie = new ArrayList<>();
List<Integer> Lisa = new ArrayList<>();
List<Integer> dipai = new ArrayList<>();
//3.2 具体的发牌动作,将索引和3取模,决定发给谁
for (int i = 0; i < list.size(); i++) {
//获取编号
Integer pokerNum = list.get(i);
//System.out.println(pokerNum);
if (i >= list.size() - 3) {
//底牌
dipai.add(pokerNum);
} else if (i % 3 == 0) {
Jake.add(pokerNum);
} else if (i % 3 == 1) {
Jennie.add(pokerNum);
} else if (i % 3 == 2) {
Lisa.add(pokerNum);
}
}
//3.3 查看玩家,底牌的编号
/*System.out.println("Jake:" + Jake);
System.out.println("Jennie:" + Jennie);
System.out.println("Lisa:" + Lisa);
System.out.println("底牌:" + dipai);*/
//4. 查看具体的牌
System.out.println("----------------------");
/*String str = printPoker(Jake, pokers);
System.out.println("Jake:" + str);*/
System.out.println("Jake:" + printPoker(Jake, pokers));
System.out.println("Jennie:" + printPoker(Jennie, pokers));
System.out.println("Lisa:" + printPoker(Lisa, pokers));
System.out.println("底牌:" + printPoker(dipai, pokers));
}
/*
4. 定义一个方法,用来看牌
方法名:printPoker
参数列表:List<Integer>, Map<Integer, String>
返回值:String
*/
public static String printPoker(List<Integer> nums, Map<Integer,String> pokers) {
//1. 对牌的编号进行升序排列
Collections.sort(nums);
//2. 遍历牌的编号集合,获取到每一个编号
StringBuilder sb = new StringBuilder();
for (Integer num : nums) {
// num就是要查找的具体牌的 编号
//3. 根据编号去双列集合中查找该编号对应的具体牌
String poker = pokers.get(num);
//4. 将获取到的牌进行拼接
sb.append(poker + " ");
}
//5. 将最后拼接结果返回即可
String str = sb.toString();
return str.trim();
}
}
运行结果