一、集合框架概述
JDK提供的集合API位于java.util内
1.1 生活中的容器
1.2 数组的特点与弊端
面向对象语言就是对事物进行对象化,为了对多个对象进行操作,需要将对象进行存储,而之前使用的数组对象存在一定的弊端;
数组的特点:
- 数组初始化后,长度就确定了;
- 数组中添加的元素是依次紧密排序,有序的、可重复的;
- 数组声明的类型,就决定了进行元素初始化时的类型,数组中元素的类型保持与初始化一致;
- 数组中可存放基本数据类型值,也可以存储引用数据类型的变量;
数组的弊端:
- 数组初始化后,长度就不可变,不便于扩展;
- 数组中提供的属性和方法少,不便于进行添加、删除、插入、获取元素个数等操作,且效率不高;
- 数组存储数据的特点单一,只能存储有序的、可以重复的数据;
Java集合框架中的类可以用于存储多个对象,还可用于保存具有映射关系的关联数组;
1.3 Java集合框架体系
Java集合可分为Collection和Map两大体系(即Java集合 = Collection接口 + Map接口):
Collection接口
Collection接口:用于存储一个一个的数据,也称为单列数据集合;
Collection接口实现路线:
-
Collection接口—List子接口—ArrayList(主要实现类)、LinkedList、Vector实现类
List子接口:用来存储有序的,可重复的数据(主要用来替换数组,“动态”数组)
实现类:ArrayList(主要实现类),LinkedList,Vector; -
Collection接口—Set子接口—HashSet(主要实现类)、LinkedHashSet、TreeSet实现类
Set子接口:用来存储无序的,不可重复的数据;
实现类:HashSet(主要实现类),LinkedHashSet,TreeSet
Map接口
Map接口用于存储具有映射关系“key-value对”的集合,即一对一对的数据,也称双列数据集合(类似于高中的函数、映射)。
实现类:HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties
1.4 集合的使用场景
二、Collection接口及方法
- JDK不提供此接口的任何直接实现,而是提供更具体的子接口;
- Collection接口是List和Set接口的父接口,该接口里定义的方法既可用于操作Set集合,也可用于操作List集合。
2.1 添加
- add(E obj):添加元素对象到当前集合中;
- addAll(Collection other):添加other集合中的所有元素对象到当前集合中;
package gather;
import java.util.ArrayList;
import java.util.Collection;
public class TestCollection {
public static void main(String[] args) {
TestCollection tc=new TestCollection();
tc.testAdd();
System.out.println();
tc.testAddAll();
}
// 添加
public void testAdd(){
Collection coll=new ArrayList();
coll.add("小小");
coll.add("笑笑");
coll.add("晓晓");
System.out.println("coll:"+coll);
}
public void testAddAll(){
Collection c1=new ArrayList();
c1.add(1);
c1.add(2);
c1.add(3);
System.out.println("c1集合元素的个数:"+c1.size());
System.out.println("c1="+c1);
Collection c2=new ArrayList();
c2.add(4);
c2.add(5);
c2.add(6);
System.out.println("c2集合元素个数:"+c2.size());
System.out.println("c2:"+c2);
Collection c3=new ArrayList();
c3.add(7);
c3.add(8);
c3.add(9);
System.out.println("c3:"+c3);
// add()和addAll()区别
c1.add(c3); //添加的是对象
System.out.println("c1.add(c3):"+c1); //[1, 2, 3, [7, 8, 9]]
c1.addAll(c3); //添加的是对象中的各元素
System.out.println("c1.addAll(c3):"+c1); //[1, 2, 3, 7, 8, 9]
}
}
2.2 判断
- int size():获取当前集合中实际存储的元素个数;
- boolean isEmpty():判断当前集合是否为空集合;
- boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素;
- boolean containsAll(Collection coll):判断coll集合中的元素是否在当前集合中都存在,即coll集合是否是当前集合的“子集”;
- boolean equals(Object obj):判断当前集合与obj是否相等;
package gather;
import java.util.ArrayList;
import java.util.Collection;
public class TestCollection_judge {
public static void main(String args[]){
TestCollection_judge.testJudge();
}
public static void testJudge(){
Collection c1=new ArrayList();
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(4);
System.out.println("c1:"+c1); //c1:[1, 2, 3, 4]
System.out.println("c1中元素的个数:"+c1.size()); //c1中元素的个数:4
System.out.println("c1是否为空:"+c1.isEmpty()); //c1是否为空:false
System.out.println("c1中是否包含1:"+c1.contains(1)); //true
Collection c2=new ArrayList();
c2.add(1);
c2.add(3);
c2.add(6);
System.out.println("c1中是否包含c2中的元素:"+c1.containsAll(c2)); //false
System.out.println("c1集合与c2集合是否相等:"+c1.equals(c2)); //false
}
}
2.3 删除
- void clear():清空集合元素;
- boolean remove(Object obj):从当前集合中删除第一个找到的与obj对象equals返回true的元素;
- boolean removeAll(Collection coll):从当前集合中删除所有与coll集合中相同的元素;
- boolean retainAll(Collection coll):从当前集合中删除两个集合中所有不同的元素,使得当前集合仅保留与coll集合中的元素相同的元素,即当前集合中仅保留两个集合的交集;
package gather;
import java.util.ArrayList;
import java.util.Collection;
public class TestCollection_clear {
public static void main(String[] args) {
TestCollection_clear.testClear();
}
public static void testClear(){
Collection c1=new ArrayList();
c1.add(1);
c1.add(2);
c1.add(3);
Collection c2=new ArrayList();
c2.add(1);
c2.add(3);
c2.add(5);
System.out.println("c1:"+c1); //[1, 2, 3]
System.out.println("c2:"+c2); //[1, 3, 5]
// c1.clear();
// System.out.println("清除后的c1:"+c1); //[]
// c1.remove(2);
// System.out.println("删除c1中的1:"+c1); //[1, 3]
// c1.removeAll(c2);
// System.out.println("删除c1中与c2相同的元素:"+c1); //[2]
c1.retainAll(c2);
System.out.println("删除c1中与c2中不同的元素:"+c1); //[1, 3]
}
}
2.4 其他
- Object[] toArray():返回包含当前集合中所有元素的数组;
- hashCode():获取集合对象的哈希值;
- iterator():返回迭代器对象,用于集合遍历;
package gather;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class TestCollection_other {
public static void main(String[] args) {
TestCollection_other.other();
}
public static void other(){
Collection c1=new ArrayList();
c1.add(1);
c1.add(2);
c1.add(3);
System.out.println("集合c1:"+c1); //[1, 2, 3]
// 集合转换为数组,集合的toArray()方法
Object[] objects=c1.toArray(); //集合c1转换成数组objects
System.out.println("用数组返回coll中所有元素:"+ Arrays.toString(objects)); //[1, 2, 3]
// 数组转换为集合,调用Arrays的asList(Object ...objs)
Object[] arr1=new Object[]{123,"AA","aa"};
Collection list=Arrays.asList(arr1);
System.out.println("用集合转换为数组:"+list); //[123, AA, aa]
}
}
三、Iterator(迭代器)接口
3.1 Iterator接口
在程序开发中,经常需要遍历集合中的所有元素,针对这种需求,JDK专门提供了一个接口java.util.Iterator。
Iterator接口也是Java集合中的一员,但它与Collection、Map接口有所不同。
Iterator与Collection、Map接口的区别
- Collection接口与Map接口主要用于存储元素;
- Iterator,被称为迭代器接口,本身并不提供存储对象的能力,主要用于遍历Collectiion中的元素;
- Collection接口继承了java.lang.Iterator接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象;
- public Iterator iterator():获取集合对应的迭代器,用来遍历集合中的元素的;
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前;
3.2 Iterator接口的常用方法如下:
- public E next():返回迭代的下一个元素;
- public boolean hasNext():如果仍有元素可迭代,则返回true;
- void remove():使用Iterator迭代器删除元素,java.util.Iterator迭代器中的方法;
注意:
- 在调用it.next()方法之前必须要调用it.hasNext()进行检测,若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。
- Iterator可删除集合的元素,但遍历过程中通过迭代器remove方法,不是集合对象的remove方法;
- 如果还未调用next()或在上一次调用next()方法之后已经调用了remove()方法,再调用remove()都会报IllegalStateException;
- Collection 已经有remove(xx)方法了,为什么Iterator迭代器还要提供删除方法呢?因为迭代器的remove()可以按指定的条件进行删除。
package gather;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class TestIterator {
public static void main(String[] args) {
TestIterator.testIterator();
}
public static void testIterator(){
Collection c1=new ArrayList(); //创建集合对象
c1.add(1);
c1.add(2);
c1.add(3);
System.out.println("c1;"+c1);
System.out.println();
Iterator c2=c1.iterator(); //获取迭代器对象
System.out.println(c2.next());
System.out.println(c2.next());
System.out.println(c2.next());
// System.out.println(c2.next());
System.out.println();
Iterator c3=c1.iterator(); //获取迭代器对象
while(c3.hasNext()){ //判断是否还有元素可进行迭代
System.out.print(c3.next()+"\t"); //取出下一个元素
System.out.println();
Iterator c4=c1.iterator();
while(c4.hasNext()){
Object obj=c4.next();
if(obj.equals("1")){
c4.remove();
}
}
}
}
}
3.3 迭代器的执行原理
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素;
图示原理:
3.4 foreach循环
foreach循环(也称增强for循环)是JDK5.0中定义的一个高级for循环,专门用来遍历数组和集合的,其增强for的内部原理其实是Iterator迭代器。
foreach循环的语法格式:
for(元素的数据类型 局部变量 : Collection集合或数组){
//操作局部变量的输出操作
}
//这里局部变量就是一个临时变量,自己命名即可
package gather;
import java.util.ArrayList;
import java.util.Collection;
public class TestForeach {
public static void main(String[] args) {
TestForeach.testForeach();
}
public static void testForeach(){
Collection c1=new ArrayList();
c1.add(1);
c1.add(2);
c1.add(3);
for(Object c:c1){
System.out.println(c);
}
int[] nums={1,2,3,4,5,6};
for (int num:nums
) {
System.out.println(num);
}
}
}
foreach增强for循环用于Collection和数组,通常只进行遍历元素,不要再遍历的过程中对集合元素进行增删操作。
四、Collection子接口1—List
4.1 List接口特点
- 鉴于Java中数组用来存储数据的局限性,我们通常使用java.util.List代替数组
- List集合类中元素有序,且可重复,集合中的每个元素都有其对应的顺序索引;
- JDK API中List接口的实现类:ArrayList、LinkedList和Vector;
4.2 List接口方法
List除了从Collection集合继承的方法外,List集合里添加了一些根据索引来操作集合元素的方法;
插入元素
- void add(int index,Object ele):在index位置插入ele元素;
- boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来;
public static void testAdd(){
// 创建List对象
List<Integer> list=new ArrayList<Integer>();
// 在尾部添加指定元素
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("list集合:"+list);
// 在指定位置插入元素
list.add(2,6);
// list.add(6,2); //插入的位置一定要在创建插入位置的内,否则出现IndexOutOfBoundException异常
System.out.println("在指定索引位置添加元素:"+list);
Collection c1=new ArrayList();
c1.add(11);
c1.add(22);
c1.add(33);
// 在指定位置插入对象中的所有元素
list.addAll(0,c1);
System.out.println("在指定索引位置添加对象:"+list);
}
获取元素
- Object get(int index):获取指定index位置的元素;
- List subList(int fromIndex,int toIndex):返回fromIndex到toIndex集合;
// 获取元素
public static void testGet(){
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("list:"+list);
// 获取指定位置的元素
System.out.println("获取指定索引位置的元素:"+list.get(2));
// 获取指定索引位置的子集
System.out.println("获取指定索引位置的子集合:"+list.subList(0,2));
}
获取元素索引
-
- int indexOf(Object obj):返回obj在集合中首次出现的位置;
- int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置;
// 获取指定元素的索引
public static void testIndex(){
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(2);
list.add(3);
System.out.println(list);
System.out.println("获取指定元素的首次出现位置的索引:"+list.indexOf(3)); //首次出现的位置
System.out.println("获取指定元素的最后出现位置的索引:"+list.lastIndexOf(3)); //末次出现的位置
}
删除和替换元素
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index,Object ele):设置指定index位置的元素为ele;
public static void testDelete(){
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(2);
list.add(1);
System.out.println("删除集合中索引所对应的指定元素:"+list.remove(1));
System.out.println("删除指定元素后的集合:"+list);
}
public static void testSet(){
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("替换集合中索引所对应的指定元素:"+list.set(1,6));
System.out.println("替换后的集合:"+list);
}
4.3 List接口的主要实现类–ArrayList
- ArrayList是List接口的主要实现类;
- 本质上,ArrayList是对象引用的一个“变长”数组;
- Arrays.asList(…):方法返回的List集合,既不是ArrayList实例,也不是Vector实例,其返回值是一个固定长度的List集合;
4.4 List的实现类–LinkedList
对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高,这是由底层采用链表(双向链表)结构存储数据决定的。
特有的方法
- void addFirst(Object obj)
- void addLast(Object obj)
- Object getFirst()
- Object getLast()
- Object removeFirst()
- Object removeLast()
4.5 List的实现类–Vector(向量)
- Vector是一个古老的集合,JDK1.0就有了,大多数操作与ArrayList相同,区别之处在于Vector是线程安全的;
- 在各种List中,最好把ArrayList作为默认选择,当插入、删除频繁时,使用LinkedList,Vector总是比ArrayList慢,所以尽量避免使用;
特有方法
- void addElement(Object obj)
- void insertElementAt(Object obj,int index)
- void setElementAt(Object obj,int index)
- void removeElement(Object obj)
- void removeAllElements()
4.6 练习
练习1:学生信息录入
题目
•定义学生类,属性为姓名、年龄,提供必要的getter、setter方法,构造器,toString(),equals()方法。
•使用ArrayList集合,保存录入的多个学生对象。
•循环录入的方式,1:继续录入,0:结束录入。
•录入结束后,用foreach遍历集合。
•代码实现;
效果图
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/49b0c806b9e640e6af0d961a4b262143.png)
代码
package gather.list;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Scanner;
public class TrainList {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
ArrayList stus=new ArrayList(); //create students information set
for(;;){ //operation
System.out.println("选择操作(录入:1,结束:0)");
int choice=sc.nextInt(); //choice operation type
if(choice==1){ //judge operation type
System.out.print("姓名:"); //name
String stuName=sc.next();
System.out.print("年龄:"); //age
int stuAge=sc.nextInt();
Student stu=new Student(stuName,stuAge); //create single student information Object
stus.add(stu);
}
else if(choice==0){
break;
}
else{
System.out.println("您的选择有误,请重新输入!");
}
}
for(Object stu:stus){ //output students information
System.out.println(stu);
}
}
}
class Student{ //create student Object
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public Student() {
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
练习2:统计元素出现次数
题目
1、请定义方法public static int listTest(Collection list,String s)统计集合中指定元素出现的次数
2、创建集合,集合存放随机生成的30个小写字母
3、用listTest统计,a、b、c、x元素的出现次数
4、效果图
效果图
代码
package gather.list;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
public class TestList_02 {
public static void main(String[] args) {
//1.随机生成含有30个小写字母的集合
Collection list = new ArrayList();//创建集合
Random rd = new Random();
for (int i = 0; i < 30; i++) {
list.add((char) (rd.nextInt(26) + 97) + "");
}
System.out.println("随机生成集合list:"+list);
System.out.println("a:"+listTest(list,"a"));
System.out.println("b:"+listTest(list,"b"));
System.out.println("c:"+listTest(list,"c"));
System.out.println("x:"+listTest(list,"x"));
}
public static int listTest(Collection list,String s){ //计数
int count=0;
for(Object obj:list){
if(s.equals(obj)){
count++;
}
}
return count;
}
}
练习3:KTV点歌系统
题目
分别使用ArrayList和LinkedList集合,编写一个KTV点歌系统的程序。在程序中:
•指令1代表添加歌曲
•指令2代表将所选歌曲置顶
•指令3代表将所选歌曲提前一位
•指令4代表退出该系统
要求根据用户输入的指令和歌曲名展现歌曲列表。例如输入指令1,输入歌曲名"爱你一万年",则输出“当前歌曲列表:[爱你一万年]”。
分析
1.为了能够指引用户快速上手操作,首先要将各个指令所表示的含义打印到控制台
2.创建一个集合作为歌曲列表,并向其添加一部分歌曲;
通过ArrayList或LinkedList集合定义的方法操作歌曲列表;
效果图
代码
package gather.list;
import java.util.ArrayList;
import java.util.Scanner;
/**
* 分别使用ArrayList和LinkedList集合,编写一个KTV点歌系统的程序。在程序中:
* •指令1代表添加歌曲
* •指令2代表将所选歌曲置顶
* •指令3代表将所选歌曲提前一位
* •指令4代表退出该系统
* 要求根据用户输入的指令和歌曲名展现歌曲列表。例如输入指令1,输入歌曲名"爱你一万年",则输出“当前歌曲列表:[爱你一万年]”。
*/
public class TestList_03 {
// 创建歌曲列表
public static ArrayList musicList=new ArrayList();
public static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
// 添加一部分歌曲至歌曲列表中
Function.addMusicList();
boolean flag=true;
while(flag){
// 对系统的功能指令进行介绍
System.out.println("当前歌曲列表:"+musicList);
System.out.println("===========Welcome To KTV System===========");
System.out.println("1.添加歌曲");
System.out.println("2.置顶歌曲");
System.out.println("3.提前歌曲");
System.out.println("4.退出系统");
System.out.println("============================================");
// 输入功能指令
System.out.println("请输入您的指令:");
int instruction=sc.nextInt();
switch (instruction){
case 1:Function.addMusic();break;
case 2:Function.setTop();break;
case 3:Function.setBefore();break;
case 4:
System.out.println("--------退出系统----------");
System.out.println("您已退出点歌系统!!!");
flag=false;
break;
default:
System.out.println("您输入的指令有误,请重新输入!!!");break;
}
}
}
}
class Function{
//添加部分歌曲
public static void addMusicList(){
TestList_03.musicList.add("西楼儿女");
TestList_03.musicList.add("我的纸飞机");
TestList_03.musicList.add("不将就");
TestList_03.musicList.add("我期待的不是雪");
TestList_03.musicList.add("熬夜");
TestList_03.musicList.add("悬溺");
}
//添加歌曲
public static void addMusic(){
System.out.println("请输入要添加的歌曲名称:");
String musicName=TestList_03.sc.next(); //获取键盘输入的歌名
TestList_03.musicList.add(musicName); //添加到歌单
System.out.println("已添加歌曲:"+musicName);
}
//置顶歌曲
public static void setTop(){
System.out.println("请输入要置顶的歌曲名称:");
String musicName=TestList_03.sc.next(); //获取键盘输入内容
int musicIndex=TestList_03.musicList.indexOf(musicName); //查找指定歌曲位置
if(musicIndex<0){ //判断输入歌曲是否存在
System.out.println("当前列表中没有输入的歌曲!!!");
}
else{
TestList_03.musicList.remove(musicName); //移除置顶的歌曲
TestList_03.musicList.add(0,musicName); //将指定的歌曲放到第一位
System.out.println("已将歌曲《"+musicName+"》置顶");
}
}
//将歌曲前置一位
public static void setBefore(){
System.out.println("请输入要前置的歌曲名称:");
String musicName=TestList_03.sc.next();
int musicIndex=TestList_03.musicList.indexOf(musicName); //查找指定歌曲位置
if(musicIndex<0){ //判断输入歌曲是否存在
System.out.println("当前歌曲列表中没有输入的歌曲!!!");
}
else if(musicIndex==0){ //判断歌曲已在第一位
System.out.println("当前歌曲已在最顶部!!!");
}
else{
TestList_03.musicList.remove(musicName);
TestList_03.musicList.add(musicIndex-1,musicName);
System.out.println("已将歌曲《"+musicName+"》前置一位");
}
}
}
五、Collection子接口2—Set
5.1 Set接口概述
- Set接口是Collection的子接口,Set接口相较于Collection接口没有提供额外的方法;
- Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加操作失败。
- Set集合支持的遍历方式和Collection集合一样:foreach和Iterator;
- Set的常用实现类有:HashSet、TreeSet、LinkedHashSet;
5.2 Set主要实现类—HashSet
5.2.1 HashSet概述
- HashSet是Set接口的主要实现类,大多数使用Set集合是都使用这个实现类;
- HashSet按Hash算法来存储集合中的元素,因此具有很好的存储,查找,删除性能;
- HashSet具有特点:
- 不能保证元素的排列顺序;
- HashSet不是线程安全的;
- 集合元素可以是null;
- HashSet集合判断两个元素相等的标准,两个对象通过**hashCode()**方法得到的哈希值相等,并且两个对象的equals()方法返回值为true;
- 对于存放在Set容器中的对象,对应的类一定要重写hashCode()和equals(Object obj)方法,以实现对象相等规则,即“相等的对象必须具有相等的散列码”;
- HashSet集合中元素的无序性,不等同于随机性,这里的无序性与元素的添加位置有关。具体来说:在添加每一个元素到数组中时,具体的存储位置是由元素的hashCode()调用后返回的hash值决定的。导致在数组中每个元素不是一次紧密存放的,表现出一定的无序性;
5.2.2 HashSet中添加元素的过程
- 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法得到该对象的hashCode值,然后根据hashCode值,通过某个散列函数决定该对象在HashSet底层数组中的存储位置;
- 如果要在数组中存储的位置上没有元素,则直接添加成功;
- 如果要在数组中存储的位置上有元素,则继续比较:
- 如果两个元素hashCode值不相等,则添加成功;
- 如果两个元素的hashCode()值相等,则会继续调用**equals()**方法;
(1) 如果equals()方法结果为false,则添加成功;
(2)如果equals()方法结果为true,则添加失败;
- 第2步添加成功 ,元素会保存在底层数组中;
- 第3步两种添加成功的操作,由于该底层数组的位置已经有元素了,则会通过链表的方式继续链接,存储;
package gather.set;
import java.util.HashSet;
import java.util.Objects;
public class TestSet_01 {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("小小");
hs.add("晓晓");
hs.add("小小");
hs.add("潇潇");
hs.add("筱筱");
System.out.println("hs:" + hs); //不允许重复,无序
HashSet set=new HashSet();
set.add(new Time(2021,1,1));
set.add(new Time(2022,1,1));
set.add(new Time(2022,1,1));
set.add(new Time(2023,1,1));
System.out.println("set:"+set); //不允许重复,无序
}
}
class Time {
private int year;
private int month;
private int day;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public Time(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public Time() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Time time = (Time) o;
return year==time.year&&
month==time.month&&
day == time.day;
}
@Override
public int hashCode() {
return Objects.hash(year,month,day);
}
@Override
public String toString() {
return "Time{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}
效果图
5.2.3 重写hashCode()方法的基本原则
- 在程序运行时,同一个对象多次调用hashCode()方法应该返回相同的值;
- 当两个对象的equals()方法比较返回true时,这两个对象的hashCode()方法的返回值也应相等;
- 对象中用作equals()方法比较的属性Field,都应该用来计算hashCode值。
注意:
如果两个元素的equals()方法返回true,但他们的hashCode()返回值不相等,hashSet将会把他们存储在不同的位置,但依然可添加成功。
5.2.4 重写equals()方法的基本原则
- 重写equals方法的时候一般都需要同时复写hashCode方法,通常参与计算hashCode的对象的属性也应该参与到equals()中进行计算;
- 推荐:开发中直接调用IDEA里的快捷键自动重写equals()和hashCode()方法即可,(快捷键:alt+insert);
素数的作用可以减少冲突。
5.3 Set主要实现类—LinkdedHashSet
- LinkedHashSet是HashSet的子类,不允许集合元素重复;
- LinkedHashSet根据元素的hashCode值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以添加顺序保存的;
- LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能;
package gather.set;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
public class TestLinkedHashSet {
public static void main(String[] args) {
LinkedHashSet linkedHashSet=new LinkedHashSet();
linkedHashSet.add(123);
linkedHashSet.add(123);
linkedHashSet.add("一二三");
linkedHashSet.add('a');
System.out.println("linkedHashSet:"+linkedHashSet);
}
}
5.4 TreeSet概述
- TreeSet是SortedSet接口的实现类,TreeSet可以按照添加的元素的指定属性的大小顺序进行遍历;
- TreeSet底层使用红黑树结构存储数据;
- 新增的方法:
- Comparator comparator()
- Object first()
- Object last()
- Object lower(Object e)
- Object higher(Object e)
- SortedSet subSet(fromElement,toElement)
- SortedSet headSet(toElement)
- SortedSet tailSet(fromElement)
- TreeSet特点:不允许重复,实现排序(自然排序或定制排序)
- TreeSet两种排序方法:自然排序和定制排序,默认情况下,TreeSet采用自然排序;
自然排序(默认排序方式)
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排序。
- 如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable接口(TreeSet中);
- 实现Comparable的类必须实现compareTo(Object obj)方法,两个对象即通过compareTo(Object obj)方法的返回值来比较大小(对象类中);
// 自然排序
public static void autoSortedTreeSet(){
TreeSet treeSet01=new TreeSet();
treeSet01.add(new User("星星",23)); //将User对象添加到TreeSet,则User类必须要实现Comparable接口
treeSet01.add(new User("萌萌",21));
treeSet01.add(new User("晴晴",22));
Iterator is=treeSet01.iterator();
System.out.println("======手动排序======");
while (is.hasNext()){
System.out.println(is.next());
}
}
//该类实现了Comparable接口
class User implements Comparable{
private String name;
private int age;
public String getName(){
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public User(){
}
public void setName(String name) {
this.name = name;
}
public User(String name, int age){
this.name=name;
this.age=age;
}
@Override
public int compareTo(Object o) { //实现Comparable接口中的compareTo()方法
if(this ==o){
return 0;
}
if(o instanceof User){
User user=(User) o;
int value=this.age-user.age;
if(value!=0){
return value;
}
return -this.name.compareTo(user.name);
}
throw new RuntimeException("输入的类型不匹配");
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
定制排序(定制排序方式)
如果元素所属的类没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其他属性大小进行排序,则考虑使用定制排序,定制排序,通过Comparator接口来实现,需要**重写compare(T o1,T o2)**方法;
- 利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2;
- 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器。
因为只有相同类的两个实例才会比较大小,所以向TreeSet中添加的应该是同一个类的对象;
对于TreeSet集合而言,它判断了两个对象那个是否相等的唯一标准是:两个对象通过compareTo(Object obj)或compare(Object o1,Object o2)方法比较返回值,返回值为0,则认为两个对象相等。
public static void manualSorted(){
Comparator comparator=new Comparator(){
@Override
public int compare(Object o1,Object o2){
if(o1 instanceof User && o2 instanceof User){
User u1=(User)o1;
User u2=(User)o2;
return u1.getName().compareTo(u2.getName());
}
throw new RuntimeException("输入的类型不匹配");
}
};
System.out.println("-------手动排序---------");
TreeSet set=new TreeSet(comparator);
set.add(new User("Tom",23));
set.add(new User("Alis",22));
set.add(new User("Jerry",24));
set.add(new User("Tommy",21));
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//User对象与自然排序相同
六、Map接口
6.1 Map的概述
Map与Collection并列存在,用于保存具有映射关系的数据:key-value
- Collection集合称为单列集合,元素是鼓励存在的(理解为单身)
- Map集合是双列集合,元素是成对存在的(理解为夫妻)
- Map中的key和value都可以是任何引用类型的数据,但常用String类作为Map的“键”;
- Map接口的常用实现类:HashMap、LinkedHashMap、TreeMap和Properties。其中HashMap是Map接口使用频率最高的实现类。
6.2 Map中key-value特点
HashMap中存储的key、value的特点如下:
- Map中的key用Set来存放,不允许重复,即同一个Map对象对应的类,须重写hashCode()和equals()方法。
- key和value之间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value,不同key对应的value可以重复。value所在的类要重写equals()方法。
- key和value构成一个entry,所有的entry彼此之间是无序的,不可重复的。
6.3 Map接口的常用方法
6.3.1 添加、修改操作
- Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中;
- void putAll(Map m):将m中的所有key-value对存放到当前map中;
//添加、修改操作
// 1.put()方法
public static void putMethod(){
HashMap hashMap=new HashMap();
hashMap.put("小小",12);
hashMap.put("晓晓",21);
hashMap.put("筱筱",22);
hashMap.put("小小",20); //该操作为修改操作
System.out.println(hashMap);
}
// 2.putAll()方法
public static void putAllMethod(){
HashMap hm=new HashMap();
hm.put("晨晨",20);
hm.put("辰辰",21);
hm.put("琛琛",22);
HashMap hm2=new HashMap();
hm2.put("AA",23);
hm2.putAll(hm);
System.out.println(hm2);
}
6.3.2 删除操作
- Object remove(Object key):移除指定key的key-value对,并返回value;
- void clear():清空当前map中所有数据;
// 删除操作
public static void deleteMethod(){
HashMap hashMap=new HashMap();
hashMap.put("AA",1);
hashMap.put("BB",2);
hashMap.put("CC",3);
hashMap.put("DD",4);
System.out.println("原集合:"+hashMap);
hashMap.remove("DD");
System.out.println("remove()方法删除key=”DD“:"+hashMap);
hashMap.clear();
System.out.println("clear()方法清空集合:"+hashMap);
}
6.3.3 元素查询的操作
- Object get(Object key):获取指定key对应的value;
- boolean containsKey(Object key):是否包含指定的key;
- boolean containsValue(Object value):是否包含指定的value;
- int size():返回map中key-value对的个数;
- boolean isEmpty():判断当前map是否为空;
- boolean equals(Object obj):判断当前map和参数对象obj是否相等;
// 元素查询
public static void queryMethod(){
HashMap hashMap=new HashMap();
hashMap.put("AA",1);
hashMap.put("BB",2);
hashMap.put("CC",3);
hashMap.put("DD",4);
hashMap.put("EE",5);
hashMap.put("FF",6);
HashMap hashMap1=new HashMap();
hashMap1.put("AA",1);
hashMap1.put("BB",2);
System.out.println("get():"+hashMap.get("FF"));
System.out.println("containsKey():"+hashMap.containsKey("FF"));
System.out.println("containsValues():"+hashMap.containsValue(6));
System.out.println("size():"+hashMap.size());
System.out.println("isEmpty():"+hashMap.isEmpty());
System.out.println("equals():"+hashMap.equals(hashMap1));
}
6.3.4 元视图操作的方法
- Set keySet():返回所有key构成的Set集合;
- Collection values():返回所有value构成的Collection集合;
- Set entrySet():返回所有key-value对构成的Set集合;
// 元视图操作方法
public static void viewMethod(){
HashMap hashMap=new HashMap();
hashMap.put("AA",1);
hashMap.put("BB",2);
hashMap.put("CC",3);
hashMap.put("DD",4);
hashMap.put("EE",5);
hashMap.put("FF",6);
System.out.println("输出所有的key--->keySet():"+hashMap.keySet());
System.out.println("输出所有的value--->values():"+hashMap.values());
System.out.println("输出所有的entry(key-value)--->entrySet():"+hashMap.entrySet());
}
6.4 Map的主要实现类—HashMap
6.4.1 HashMap概述
- HashMap是Map接口使用频率最高的实现类;
- HashMap是线程不安全的,允许添加null键和null值;
- 存储数据采用的哈希表结构,底层使用一维数组+单向链表+红黑树进行key-value数据的存储,与HashSet一样,元素的存储顺序不能保证一致;
- HashMap判断两个key相等的标准是:两个key的hashCode值相等,通过equals()方法返回true。
- HashMap判断两个value相等的标准是:两个value通过equals()方法返回true;
练习
练习1:添加喜欢的歌手以及其歌手唱过的歌曲
```java
package gather.map;
import java.util.ArrayList;
import java.util.HashMap;
public class HashMapTest {
public static void main(String[] args) {
HashMapTest.singer();
}
public static void singer(){
HashMap singers=new HashMap();
ArrayList songs1=new ArrayList();
String singer1="周杰伦";
songs1.add("双节棍");
songs1.add("本草纲目");
songs1.add("夜曲");
songs1.add("稻香");
singers.put(singer1,songs1);
String singer2="陈奕迅";
ArrayList songs2=new ArrayList();
songs2.add("浮夸");
songs2.add("十年");
songs2.add("红玫瑰");
songs2.add("好久不见");
songs2.add("孤勇者");
singers.put(singer2,songs2);
System.out.println(singers);
}
}
运行结果:
练习2:统计字符串中元素个数
package gather.map.trains;
import java.util.HashMap;
import java.util.Scanner;
/**
* 统计字符串中每个字符出现的次数
*/
public class WordCountTest {
public static void main(String[] args) {
WordCountTest.wordCount();
}
public static void wordCount(){
// String str="abcddeagihkgjaoijiajkrzlnbghrggijlejgojahgni";
Scanner scanner=new Scanner(System.in);
System.out.println("请随机输入字符串:");
String str=scanner.next();
char[] chars=str.toCharArray();
HashMap hm=new HashMap();
for(char c:chars){
if(!hm.containsKey(c)){
hm.put(c,1);
}
else{
hm.put(c,(int)hm.get(c)+1);
}
}
for(Object key:hm.keySet()){
System.out.print(key+"="+hm.get(key)+"\t");
}
}
}
6.5 Map的实现类(二)—LinkedHashMap
- LinkedHashMap是HashMap的子类;
- 存储数据采用的哈希表结构+链表结构,在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的先后顺序,可保证遍历元素时,与添加的顺序一致;
- 通过哈希表结构可以保证键的唯一,不重复,需要键所在类重写hashCode()方法,equals()方法;
package gather.map;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class LinkedHashMapTest {
public static void main(String[] args) {
LinkedHashMapTest.testLinkedHashMapMethod();
}
/**
* key相同,新的value会覆盖原来的value
* 因为String重写了hashCode和equals方法
*/
public static void testLinkedHashMapMethod(){
LinkedHashMap linkedHashMap=new LinkedHashMap();
linkedHashMap.put("AA",12.0);
linkedHashMap.put("BB",23.0);
linkedHashMap.put("DD",34.0);
linkedHashMap.put("CC",45.0);
linkedHashMap.put("CC",88.0);
// 遍历的顺序与添加时的顺序一致
System.out.println(linkedHashMap.entrySet());
// HashMap支持key和value为null值
String name=null;
Integer age=null;
linkedHashMap.put(name,age);
Set entrySet=linkedHashMap.entrySet();
for(Object obj:entrySet){
Map.Entry entry=(Map.Entry)obj;
System.out.println(entrySet);
}
}
}
6.6 Map的实现类(三)—TreeMap
- TreeMap存储key-value对时,需要根据key-value对进行排序,TreeMap可以保证所有的key-value对处于有序状态;
- TreeSet底层使用红黑树结构存储数据;
- TreeMap 的 Key 的排序:
- 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException;
- 定制排序:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口;
- TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。
public class TestTreeMap {
/*
* 自然排序举例
* */
@Test
public void test1(){
TreeMap map = new TreeMap();
map.put("CC",45);
map.put("MM",78);
map.put("DD",56);
map.put("GG",89);
map.put("JJ",99);
Set entrySet = map.entrySet();
for(Object entry : entrySet){
System.out.println(entry);
}
}
/*
* 定制排序
*
* */
@Test
public void test2(){
//按照User的姓名的从小到大的顺序排列
TreeMap map = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return u1.name.compareTo(u2.name);
}
throw new RuntimeException("输入的类型不匹配");
}
});
map.put(new User("Tom",12),67);
map.put(new User("Rose",23),"87");
map.put(new User("Jerry",2),88);
map.put(new User("Eric",18),45);
map.put(new User("Tommy",44),77);
map.put(new User("Jim",23),88);
map.put(new User("Maria",18),34);
Set entrySet = map.entrySet();
for(Object entry : entrySet){
System.out.println(entry);
}
}
}
class User implements Comparable{
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/*
举例:按照age从小到大的顺序排列,如果age相同,则按照name从大到小的顺序排列
* */
@Override
public int compareTo(Object o) {
if(this == o){
return 0;
}
if(o instanceof User){
User user = (User)o;
int value = this.age - user.age;
if(value != 0){
return value;
}
return -this.name.compareTo(user.name);
}
throw new RuntimeException("输入的类型不匹配");
}
}
6.7 Map实现类(四)—Hashtable
- Hashtable是Map接口的古老实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。
- Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构(数组+单向链表),查询速度快。
- 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
- Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
- 与HashMap不同,Hashtable 不允许使用 null 作为 key 或 value。
Hashtable和HashMap的区别
HashMap:底层是一个哈希表(jdk7:数组+链表;jdk8:数组+链表+红黑树),是一个线程不安全的集合,执行效率高
Hashtable:底层也是一个哈希表(数组+链表),是一个线程安全的集合,执行效率低
HashMap集合:可以存储null的键、null的值
Hashtable集合,不能存储null的键、null的值
Hashtable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。所以HashMap是Map的主要实现类,Hashtable是Map的古老实现类。
Hashtable的子类Properties(配置文件)依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合
6.8 Map实现类(五)—Properties
- Properties 类是 Hashtable 的子类,该对象用于处理属性文件;
- 由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型,常用于处理属性文件;
- 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法;
@Test
public void test01() {
Properties properties = System.getProperties();
String fileEncoding = properties.getProperty("file.encoding");//当前源文件字符编码
System.out.println("fileEncoding = " + fileEncoding);
}
@Test
public void test02() {
Properties properties = new Properties();
properties.setProperty("user","songhk");
properties.setProperty("password","123456");
System.out.println(properties);
}
@Test
public void test03() throws IOException {
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);
七、Collections工具类
7.1 常用方法
Collections中提升了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提升了对集合对象设置不可变、对集合对象实现同步控制等方法(均为static方法);
7.1.1 排序操作
- reverse(List):反转List中元素的顺序;
- shuffle(List):对List集合元素进行随机排序;
- sort(List):根据元素的自然顺序对指定List集合元素按升序排序;
- sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序;
- swap(List ,int, int):将指定list集合中的i处元素和j处元素进行交换;
7.1.2 查找
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素;
- Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素;
- Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素;
- int binarySearch(List list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
- int binarySearch(List list,T key,Comparator c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。
- int frequency(Collection c,Object o):返回指定集合中指定元素的出现次数
7.1.3 复制、替换
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
- 提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx的不可修改的视图。
7.1.4 添加
- boolean addAll(Collection c,T… elements)将所有指定元素添加到指定 collection 中;
7.1.5 同步
- Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题:
package com.cmy.collections;
import org.junit.Test;
import java.text.Collator;
import java.util.*;
public class TestCollections {
@Test
public void test01(){
/*
public static <T> boolean addAll(Collection<? super T> c,T... elements)
将所有指定元素添加到指定 collection 中。Collection的集合的元素类型必须>=T类型
*/
Collection<Object> coll = new ArrayList<>();
Collections.addAll(coll, "hello","java");
Collections.addAll(coll, 1,2,3,4);
Collection<String> coll2 = new ArrayList<>();
Collections.addAll(coll2, "hello","java");
//Collections.addAll(coll2, 1,2,3,4);//String和Integer之间没有父子类关系
}
@Test
public void test02(){
/*
* public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
* 在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
*
* public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)
* 在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
*
*/
List<Man> list = new ArrayList<>();
list.add(new Man("张三",23));
list.add(new Man("李四",24));
list.add(new Man("王五",25));
/*
* Man max = Collections.max(list);//要求Man实现Comparable接口,或者父类实现
* System.out.println(max);
*/
Man max = Collections.max(list, new Comparator<Man>() {
@Override
public int compare(Man o1, Man o2) {
return o2.getAge()-o2.getAge();
}
});
System.out.println(max);
}
@Test
public void test03(){
/*
* public static void reverse(List<?> list)
* 反转指定列表List中元素的顺序。
*/
List<String> list = new ArrayList<>();
Collections.addAll(list,"hello","java","world");
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
@Test
public void test04(){
/* public static void shuffle(List<?> list)
* List 集合元素进行随机排序,类似洗牌,打乱顺序
*/
List<String> list = new ArrayList<>();
Collections.addAll(list,"hello","java","world");
Collections.shuffle(list);
System.out.println(list);
}
@Test
public void test05() {
/* public static <T extends Comparable<? super T>> void sort(List<T> list)
* 根据元素的自然顺序对指定 List 集合元素按升序排序
* public static <T> void sort(List<T> list,Comparator<? super T> c)
* 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
*/
List<Man> list = new ArrayList<>();
list.add(new Man("张三",23));
list.add(new Man("李四",24));
list.add(new Man("王五",25));
Collections.sort(list);
System.out.println(list);
Collections.sort(list, new Comparator<Man>() {
@Override
public int compare(Man o1, Man o2) {
return Collator.getInstance(Locale.CHINA).compare(o1.getName(),o2.getName());
}
});
System.out.println(list);
}
@Test
public void test06(){
/* public static void swap(List<?> list,int i,int j)
* 将指定 list 集合中的 i 处元素和 j 处元素进行交换
*/
List<String> list = new ArrayList<>();
Collections.addAll(list,"hello","java","world");
Collections.swap(list,0,2);
System.out.println(list);
}
@Test
public void test07(){
/* public static int frequency(Collection<?> c,Object o)
* 返回指定集合中指定元素的出现次数
*/
List<String> list = new ArrayList<>();
Collections.addAll(list,"hello","java","world","hello","hello");
int count = Collections.frequency(list, "hello");
System.out.println("count = " + count);
}
@Test
public void test08(){
/* public static <T> void copy(List<? super T> dest,List<? extends T> src)
* 将src中的内容复制到dest中
*/
List<Integer> list = new ArrayList<>();
for(int i=1; i<=5; i++){//1-5
list.add(i);
}
List<Integer> list2 = new ArrayList<>();
for(int i=11; i<=13; i++){//11-13
list2.add(i);
}
Collections.copy(list, list2);
System.out.println(list);
List<Integer> list3 = new ArrayList<>();
for(int i=11; i<=20; i++){//11-20
list3.add(i);
}
//java.lang.IndexOutOfBoundsException: Source does not fit in dest
//Collections.copy(list, list3);
//System.out.println(list);
}
@Test
public void test09(){
/*public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal)
* 使用新值替换 List 对象的所有旧值
*/
List<String> list = new ArrayList<>();
Collections.addAll(list,"hello","java","world","hello","hello");
Collections.replaceAll(list, "hello","song");
System.out.println(list);
}
}