Java
常用工具
集合
集合,即集,是用来存储多个元素的容器
集合与数组的区别
- 元素类型:
集合:引用类型(存储基本类型时自动装箱)
数组:基本类型、引用类型 - 元素个数:
集合:不固定,可任意扩容
数组:固定,不能改变容量
集合的好处
不受容器大小限制,可以随时添加、删除元素
提供了大量操作元素的方法(判断、获取等)
Java
的集合体系
单列集合(Collection
)
List
: ArrayList
Set
: HashSet
双列集合(Map: key, value
)
Map
: HashMap
List
集合的特点与应用
特点:
可重复、有序(存取顺序相同)
应用:
List list = new ArrayList();
List
接口的成员方法:
-
public boolean add(E e)
添加元素到集合的末尾,E
是泛型的意思 -
public E get(int index)
根据索引,搜索对应的元素 -
public int size()
获取集合的长度
List
是接口,可通过创建其子类ArrayList
对象来完成该接口的实例化
List list = new ArrayList();
代码:
package cn.itcast.demo1;
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 +
'}';
}
}
package cn.itcast.demo1;
import java.util.ArrayList;
import java.util.List;
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("虚竹",38);
Student s4 = new Student("段誉",26);
//3. 将元素对象添加到集合对象中.
/*boolean b1 = list.add(s1);
System.out.println(b1);
boolean b2 = list.add(s1);
System.out.println(b2);*/
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());
System.out.println("-------------------");
//4. 遍历集合.
for (int i = 0; i < list.size(); i++) {
//i表示的就是集合中每个元素的索引
//获取元素
Object obj2 = list.get(i);
System.out.println("索引为 " + i + "的元素是: " + obj2 );
}
}
}
增强 for
循环和迭代器
增强 for
循环
增强 for
循环可以简化数组和集合的遍历,是迭代器的简写形式
格式:
for (数据类型 变量名:数组或者集合对象) {
// 循环体,变量即元素
}
package cn.itcast.demo2;
import java.util.ArrayList;
import java.util.List;
*/
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 ii = (Integer)obj;
System.out.println(ii);
}
System.out.println("-------------------");
for (Object obj : list) {
Integer ii = (Integer)obj;
System.out.println(ii);
}
}
}
IDEA 快捷键:iter + 回车
迭代器
对过程的迭代,称为迭代
迭代器是遍历 Collection
集合的通用方式,可以对集合进行遍历
列表迭代器是 List
体系独有的遍历方式, 可以在对集合遍历的同时进行添加、删除等操作。
但是必须通过调用列表迭代器的方法来实现.
常用方法:
next()
:
返回迭代的下一个元素对象hasNext()
:
如果仍有元素可以迭代,则返回true
用法:
根据集合对象,获取其对象的迭代器对象
案例:
package cn.itcast.demo2;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class CollectionDemo {
public static void main(String[] args) {
// 迭代器
List list2 = new ArrayList();
list2.add("a");
list2.add("b");
list2.add("c");
/* Iterator it = list2.iterator();
// 判断迭代器中是否有元素
while(it.hasNext()) {
// 如果有元素,就一直迭代(遍历)
// 如果有就获取元素
String s = (String)it.next();
if ("b".equals(s)) {
// 常量与变量的比较,一般把常量写在前面
// 可以规避 空指针异常
// 下面的操作会报异常(并发修改异常)
// ConcurrentModificationException
list2.add("Java");
}
System.out.println(i);
}*/
// 列表迭代器
ListIterator lit = list2.listIterator();
while(lit.hasNext()) { // 如果有元素,就一直迭代(遍历)
// 如果有就获取元素
String s = (String)lit.next();
if ("b".equals(s)) {
// 常量与变量的比较,一般把常量写在前面
// 可以规避 空指针异常
lit.add("Java");
}
System.out.println(s);
}
System.out.println("---------");
System.out.println(list2);
}
}
总结:
普通的迭代器(Iterator
)在遍历集合的同时不能添加或者删除元素, 否则会报: 并发修改异常 (ConcurrentModificationException
)
列表迭代器(ListIterator
)在遍历集合的同时可以修改集合中的元素(添加, 删除等),必须使用列表迭代器中的方法.
泛型
泛型,即泛指任意类型,又叫参数化类型(Parameterized Type),对具体类型的使用起到辅助作用,类似于方法的参数
集合类泛型:表示该集合中存放指定类型的元素
示例:
// 给 List 集合加上泛型 Student
List<Student> list = new ArrayList<>();
泛型,可以保证类型安全,避免了类型转换
package cn.itcast.demo4;
import java.util.ArrayList;
import java.util.List;
/*
泛型一般只和集合类相结合使用.
泛型是JDK5的新特性, 但是从JDK7开始,后边的泛型可以不用写具体的数据类型了(菱形泛型.)
*/
public class Test {
public static void main(String[] args) {
//不使用泛型的集合
//1. 创建集合对象.
List list1 = new ArrayList();
//2. 创建元素对象.
//3. 将元素对象添加到集合对象中
list1.add("a");
list1.add("b");
list1.add("c");
//list1.add(10); 会报类型转换异常(ClassCastException)
//4. 遍历集合.
for (Object obj : list1) {
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);
}
}
}
Colletions
工具类
Collections
工具类,是针对集合进行操作的工具类
成员方法
-
sort(List<T>, Comparator<T>)
根据比较器规则对列表进行排序 -
max(Collection<T>)
返回集合的最大元素 -
reverse(List<T>)
反转List
集合元素 -
shuffle(List<T>)
使用默认的随机源随机置换指定的列表
package cn.itcast.demo5;
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);
}
}
Set
集合的特点与应用
特点:
不可重复(唯一)、无序(元素的存取顺序不一致)
应用:
Set<T> set = new HashSet<>();
向集合中添加元素的方法为:add()
遍历集合的方式:迭代器
获取集合中元素个数的方法:size()
package cn.itcast.demo6;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
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("虚竹", 38);
Student s3 = new Student("段誉", 26);
Student s4 = new Student("乔峰", 41);
Student s5 = new Student("虚竹", 38);
//3. 将集合对象添加到元素对象中.
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
//4. 遍历集合.
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);
}
}
}
但是如果是自定义类型,set 中可能出现”重复元素“
为什么 Set 集合中没有”去重“?
因为,
Set
集合保证元素的唯一性,依赖于:equals()
与hashCode()
两个方法;
如果在自定义类中,没有重写这两个方法,默认调用的是Object
类中的这两个方法,Object
类中的equals()
方法默认比较的是 地址值是否相同解决方法:
重写这两个方法
package cn.itcast.demo6;
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);
}
}
Map
集合的特点
特点:
双列集合,元素由键值对(Entry)构成:key -- value
key
: 不可以重复
value
: 可以重复
应用:
Map<T1, T2> map = new HashMap<>();
T1: 表示键的数据类型.
T2: 表示值的数据类型
成员方法:
put(K key,V value);
添加元素(键值对的形式);
元素第一次添加,返回 null
,
重复添加,会用新值覆盖旧值,并返回旧值.
get(Object key);
根据键获取其对应的值
Set<K> keySet();
获取所有键的集合.
遍历集合的方式:
- 获取所有的
key
:keySet()
- 遍历
keySet
,通过key
获取value
:get()
遍历 keySet
的方法:iterator()
package cn.itcast.demo1;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
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. 将元素对象添加到集合中.
/*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(3);
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 + "..." + value);
}
}
}
案例
package cn.itcast.demo2;
import java.util.*;
/*
需求: 模拟斗地主发牌
步骤:
1. 买牌.
2. 洗牌.
3. 发牌.
4. 看牌.
*/
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;
//将牌的编号, 具体的牌放到双列集合中.
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> liuyifei = new ArrayList<>();
List<Integer> zhaoliying = new ArrayList<>();
List<Integer> xiaohei = 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) {
liuyifei.add(pokerNum);
} else if(i % 3 == 1) {
zhaoliying.add(pokerNum);
} else if(i % 3 == 2) {
xiaohei.add(pokerNum);
}
}
/*//3.3 查看玩家, 底牌的编号.
System.out.println("liuyifei: " + liuyifei);
System.out.println("zhaoliying: " + zhaoliying);
System.out.println("xiaohei: " + xiaohei);
System.out.println("dipai: " + dipai);*/
//4. 查看具体的牌
System.out.println("----------------------------------");
/*String str = printPoker(liuyifei, pokers);
System.out.println("liuyifei: " + str);*/
System.out.println("liuyifei: " + printPoker(liuyifei, pokers));
System.out.println("zhaoliying: " + printPoker(zhaoliying, pokers));
System.out.println("xiaohei: " + printPoker(xiaohei, pokers));
System.out.println("dipai: " + 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();
}
}