- 💖作者简介:大家好,我是 爪哇小白2021。
- 半路出家的程序员,在从事开发之前在 某省测绘院 玩了一年的飞机,机缘巧合之下发现了更有趣的事情,虽然是个菜鸟但仍然热爱生活…之前喜欢用摄影记录生活,现在改用文字记录啦~
- ps:同时也是一个不太正经的航拍选手!
- 💬 总结:记录自己的学习历程,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🖊
- ✉️ 如果你想跟树说话,就化成阵风;如果你想跟木材说话,得化成火;如果你想跟灰烬讲话,得化成水。可是你要跟人说话,你也还是个人,处理人的问题是个难题。
1 集合框架的引入
1.1 集合的引入
时间过去了那么久,还记得我们当时没有学集合的之前的日子吗? 哇那个时候真的是一个遥远的日子,我迄今尤记得大概是某个深夜…有感而发有点跑题…
在这之前,大概用三种容器进行数据的存储:
1)变量空间中就可以保存数据;
2)数组中可以保存多个类型相同的数据;
3)字符串缓冲区中可以保存任何的数据;
这个是完全没有问题的,但是为什么会有集合的产生呢?假如现在给你一个很简单的问题
需求:使用数组存储3个学生对象,然后遍历并输出。
这个很简单:
分析:
我们之前只学习过创建数组存储基本数据类型常量数据,比如创建一个数组来存储整数类型。那么我们可以这样做:假设存储int类型数据,创建int数组,
int[] arr=new int[3];
假设我们要存储String类型的数据,则需要创建String类型的数组,
String[] arr=new String[3];
but
我先现在要去存贮Student类型的数据,所以这里我们应该创建Student类型的数组,·Student[]·,由于String类和Student都是类,只不过Student类是我们自定义类,所以我们可以按照定义String类型的数组去定义Student类型的数组。
实现的步骤:
1):创建学生类
2):创建学生数组
3):创建学生对象
4):添加学生到数组
5):遍历数组
贴图代码:
Demo
package com.xiaobai.jihefuxi.pojo;
public class ArrayDemo {
public static void main(String[] args) {
//创建Student类型的数组
Student[] arr=new Student[3];
//创建Student类的对象
Student s1=new Student("heixuanfeng",19);
Student s2=new Student("bandao",18);
Student s3=new Student("zhujiao",20);
//将学生对象存储到数组中
arr[0]=s1;
arr[1]=s2;
arr[2]=s3;
//遍历数组
for (int i = 0; i < arr.length; i++) {
//通过数组名和下标取出Student类的数组中的数据 arr[i]
Student s=arr[i];
//输出数据
//System.out.println(s.getName()+"====="+s.getAge());
System.out.println(s);//Student类已经复写了Object类的toString()函数直接输出
}
}
}
======控制台输出
流程图如下↓
这可能是初学者第一眼就给出的答案,虽然但是:虽然能出结果,但是太麻烦了不是吗?
因为到目前为止【没有接触集合框架…】我们只学习了三种存储数据的容器:变量 、数组、字符串缓冲区。
1)上述我们使用的是数组来存储类的对象,那其他两种容器能否替代数组并简化代码的书写呢,答案是否定的,
因为首先要排除变量,变量只能保存具体的一个值,而上述有三个对象需要保存,所以变量不可以。
补充:在这里需要强调一点,对于基本数据类型变量或者叫做普通变量空间只能保存基本数据类型,不能保存对象,而引用变量是可以保存对象的,但是引用变量只能保存一个对象。
2)其次对于字符串缓冲区,虽然字符串缓冲区可以存储对象,但是最后把这些对象数据都变成字符串进行处理,如果将对象变成字符串就不能按照像对象那样调用类中的函数进行操作了,失去了对象的意义,所以字符串缓冲区也不合适。
那我们是否还有除了数组更简单的办法吗?
如果按照我们之前的知识,在这里我们只能使用数组,但是今天我们又会学习一个新的容器,就是集合容器可以解决上述办法,并且还可以简化上述代码的书写。
什么是集合?
集合也是一种容器,也可以存放数据。随着我们学习技术的深入,那么我们在程序中创建的对象也会越来越多。这时在程序中就要想办法先把这些对象给存储起来,然后在需要使用这些对象的时候从容器中把对象取出,再去使用这些对象。
1.2 集合与数组的区别
既然引入了,肯定要对比,就好比我以前骑电动车上班,现在突然坐车上班了,为啥?你说不知道,别人心里肯定会想:你个?b。
1)从长度来讲:
数组:需要固定长度。
集合:长度可以改变,可以根据保存的数据进行扩容。
2)从存储内容上:
数组:可以存储基本类型数据,还可以存储引用类型的数据(比如:String和上述演示的Student类)。
集合:只能存储引用类型的数据,也就是说集合只能存储类的对象。
3)从存储类型上:
数组:只能存储相同类型的数据。
集合:可以存储不同类型的数据,集合中可以存储任意类型的引用数据类型。
我一眼就看出了你的小把戏!
1.3 集合框架的继承体系
集合是用来存储数据的一类容器,但是在使用集合存储数据时,也会有不同的存储需求。例:存储的数据不能有重复的、存储的数据可以自动排序、存储的数据无序。针对不同的存储需求,java设计了存储不同需求的集合对象。这些针对不同需求的集合对象,虽然存储方法式不同,但是都具有共性的功能:比如:
增、删、改、查(CRUD create read update delete)
等操作。
所以我们把共性的操作向上抽取,最终形成了一个集合框架的继承体系结构。 有时候能抽就抽,但是有时候也不是一定要抽出来才好,只能说具体问题具体分析对啦
既然有上述的共性的规律,于是Java就把这些最基本的规律抽取到了一个接口中。其中一个顶级接口就是:
Collection接口。
在集合框架体系中用接口来定义所有集合操作的共性规则。
集合体系框架从JDK1.2才开始存在。早期有集合,但是它们没有形成一个体系。
这个东西看源码就好了,或者去查资料自己研究,挺好玩的我觉得。
贴心的我附赠了一张小图~
说明:
1)Collection是这个体系的顶级接口;
2)Collection中定义了所有集合子类的共性操作;
3)我们先从Collection接口开始学习,将Collection中的函数学完之后,实现类都可以直接使用,最后我们在去学习子类特有的函数就可以了;
4)通过查阅API得知Collection、List、Set接口下面不是只有如上图所示的子类或者子接口,但是我们在开发中主要使用这些集合;
2 集合Collection
讲道理,这个东西我也就翻了下jdk帮助文档,大概了解了一下,如果漏了某些重要的属性,麻烦大哥们评论讲一讲,然后我学习下~
2.1 Collection接口介绍
单列集合
Collection接口:它是集合的最顶层接口,它中规定了所有集合中的最基本的操作规律。而Java中提供的所有集合容器都保存在java.util包下。
Collection接口是集合的顶层接口,它下面有子接口或者间接的实现类,而具体的实现类中有些可以保存重复元素,有些不能保存重复元素,有些可以保证数据有序,一些则无序。
对了 对于小白而言 在学习集合框架的时候,遇到的所有E类型,全部理解成Object类型。反正吧好理解。
2.1.1 添加方法
说明:把指定的引用类型数据,添加到集合中。添加成功则返回true。
我们知道Collection是接口,它不能new对象。而Collection中定义的是所有集合共性的操作规律。那么我们就可以随便找个Collection的实现类,例如ArrayList类。这样就可以使用多态
的方式来操作集合。
代码举例:Collection coll=new ArrayList();//这里发生多态
☆ 步骤和分析:
1)使用new关键字创建集合类ArrayList的对象,对象的类型是接口Collection;
2)使用集合对象coll调用add()函数给集合中添加不同的数据;
package com.xiaobai.jihefuxi.pojo;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionAddDemo {
public static void main(String[] args) {
/*
* 由于Collection是接口,所以不能创建Collection接口的对象,
* 但是我们可以使用new关键字创建Collection接口下面的任意一个类的对象,然后对象类型变为Collection
*/
Collection coll=new ArrayList();//这里发生多态了
//使用coll对象调用add函数向集合中添加引用类型数据
coll.add("aaaa");
//创建学生对象
Student s = new Student("爪哇小白2021",22);
//将自定义类的对象添加到集合中
coll.add(s);
/*
* 在集合中是否可以存储基本数据类型?
* 正常情况是不可以的,但是从jdk5之后,有了自动装箱和拆箱的功能
* 如果使用集合添加基本数据类型,实则jvm是把基本数据类型包装成了对应的包装类对象并存储到集合中了
*/
//Integer valueOf = Integer.valueOf(123);
coll.add(123);//这里相当于coll.add(Integer.valueOf(123));
//Boolean valueOf = Boolean.valueOf(true);
coll.add(true);//这里相当于coll.add(Boolean.valueOf(true));
//输出集合中的数据
System.out.println(coll);
}
}
控制台输出:------------------------------>
说明:【初学者可能理解的比较慢一点,把上面的代码copy一份自己在本地跑一遍就知道啦】
1)add函数可以把一个对象保存在集合中,但是这个函数有返回值boolean,返回的结果是告诉我们是否给集合中添加成功。添加成功则返回true。
2)能否给集合中保存基本类型数据?
严格意义上讲是不可以的,因为集合中只能保存引用类型数据,而基本类型数据不属于引用类型数据,即不属于对象,但是在jdk5之后,基本数据类型有自动装箱和拆箱的机制,因此我们也可以直接把基本类型的数据保存到集合中。
可是集合中存储的根本不是基本类型的数据,而是基本类型数据对应的包装类型的对象。
如:coll.add(100);//此代码存在装箱 coll.add(Integer.valueOf(100));
2.2.2 删除方法
步骤:
1)创建集合对象coll;
2)使用集合对象coll调用add()函数向集合中添加数据;
3)输出集合中的数据;
4)使用集合对象coll调用remove()函数删除指定的数据,并使用布尔类型的数据接收删除返回值boo;
5)输出返回值boo和删除后的数据coll;
根据指定的元素,删除集合中对应的元素。删除成功则返回true,否则返回false。
package com.xiaobai.jihefuxi.pojo;
import java.util.ArrayList;
import java.util.Collection;
/**
* Collection接口中的删除方法remove演示
*/
public class CollectionRemoveDemo {
public static void main(String[] args) {
//创建集合类对象
Collection coll=new ArrayList();
//使用集合对象coll给集合中添加数据
coll.add("abc");
coll.add("aaa");
coll.add("ddd");
coll.add("aaa");
coll.add("yyy");
//输出集合中的数据
System.out.println(coll);
//使用集合对象coll调用remove删除函数
boolean boo = coll.remove("aaa");
// boolean boo1 = coll.remove("aaa");
// boolean boo = coll.remove("xxx");//由于要删除的元素不在集合中,所以返回结果是false
System.out.println(boo);
// System.out.println(boo1);
System.out.println(coll);
}
}
控制台输出==============>
清空集合中所有的存储的元素。
步骤:
1)使用集合对象coll调用clear()函数清空集合中的所有元素;
2)输出清空后的集合;
可以自行演示下,仿照上面样例。
说明:
使用clear()函数清空集合中的元素后,集合容器依然存在,所以还可以继续向集合中添加元素。
问题:把集合设为null和使用集合对象中的clear()方法有什么区别?
集合=null 表示这个集合对象没有任何引用了。如:coll=null,那么堆中对象的空间就没有任何指向他了,而栈中的coll引用变量空间是一个空指向,所以这里会报空指针异常。
集合.clear() 表示集合中存储的元素全部清空,但是集合对象还存在。
2.2.3 判断方法
boolean contains(Object obj)函数表示判断集合中是否存在指定的元素。
如果有指定的元素,则返回true,没有则返回false。
讲真,判断日后用的地方还多的一比…
boolean isEmpty() 判断集合是否为空。集合中没有存储任何元素表示为空。
注意:
1)这个函数不是集合引用是否为null,而是判断集合中是否有元素;
2)如果集合中有元素返回false,集合中不包含元素则返回true。
步骤:
1)创建集合对象coll;
2)使用集合对象coll调用add()函数向集合中添加数据;
3)使用集合对象coll调用contains()函数判断集合某个数据是否在集合中,如果有返回true,否则返回false;
4)使用集合对象coll调用clear()函数清除集合中的所有数据;
5)使用集合对象coll调用isEmpty()函数判断集合中元素是否有数据,如果有数据则返回false,没有数据则返回true;
public class CollectionContainsAndIsEmptyDemo {
public static void main(String[] args) {
//创建集合对象
Collection coll=new ArrayList();
//给集合添加数据
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//使用Collection接口中的contains()函数判断某个对象是否在集合中
//如果有,则返回true,如果没有,则返回false
boolean boo = coll.contains("aaa");
System.out.println(boo);
//输出集合数据
System.out.println(coll);
//判断集合中是否有数据,如果有数据则返回false,没有数据则返回true
boolean boo1 = coll.isEmpty();
System.out.println(boo1);
//清空集合中的数据
coll.clear();
boolean boo2 = coll.isEmpty();
System.out.println(boo2);
}
2.2.4 获取元素个数
说明:获取集合中存储元素的个数(集合的大小)。
2.2.5 Collection接口中带All的方法
boolean addAll(Collection c)表示把c集合中的元素全部添加到当前调用这个方法的集合中。
分析和步骤:
1)使用new关键字创建集合类ArrayList的两个对象coll和coll2,两个对象的类型是接口Collection;
2)使用coll和coll2对象分别调用add()函数给集合添加数据;
3)使用coll2对象调用addAll()函数,coll集合对象作为该函数的参数,最后输出coll2的结果;
代码实现如下:
/*
* Collection接口中addAll方法的演示
*/
public class CollectionAddAllDemo {
public static void main(String[] args) {
/*
* 由于Collection是接口,所以不能创建Collection接口的对象,
* 但是我们可以使用new关键字创建Collection接口下面的任意一个类的对象,然后对象类型变为Collection
*/
Collection coll=new ArrayList();//这里发生多态了
//再创建一个集合对象
Collection coll2=new ArrayList();
//使用coll对象调用add函数向集合中引用类型添加数据
coll.add("aaaa");
coll.add("bbbb");
coll.add("dddd");
coll.add("eeee");
//向集合coll2中添加数据
coll2.add("AAAA");
//将集合coll中的数据添加到集合coll2中
coll2.addAll(coll);
//输出集合中的数据
System.out.println(coll2);
}
}
说明:判断集合中是否包含指定集合中的所有元素。
containsAll()方法是要求作为参数传递的集合中的元素需要全部在调用这个方法的集合中存在,才会返回true。
分析和步骤:
1)使用new关键字创建集合类ArrayList的两个对象coll和coll2,两个对象的类型是接口Collection;
2)使用coll和coll2对象分别调用add()函数给集合添加数据;
3)使用coll对象调用containsAll()函数,coll2集合对象作为该函数的参数,最后输出布尔类型的返回结果;
/*
* Collection接口中containsAll方法的演示
*/
public class CollectionContainsAllDemo {
public static void main(String[] args) {
/*
* 由于Collection是接口,所以不能创建Collection接口的对象,
* 但是我们可以使用new关键字创建Collection接口下面的任意一个类的对象,然后对象类型变为Collection
*/
Collection coll=new ArrayList();//这里发生多态了
//再创建一个集合对象
Collection coll2=new ArrayList();
//使用coll对象调用add函数向集合中引用类型添加数据
coll.add("aaaa");
coll.add("bbbb");
coll.add("dddd");
coll.add("eeee");
//向集合coll2中添加数据
coll2.add("AAAA");
//将集合coll中的数据添加到集合coll2中
coll2.addAll(coll);
//coll 集合:"aaaa" "bbbb" "dddd" "eeee"
//coll2 集合:"AAAA" "aaaa" "bbbb" "dddd" "eeee"
//判断集合coll中是否包含集合coll2中的所有集合,如果包含返回true,否则返回false
//boolean boo = coll.containsAll(coll2);//false 不包含
boolean boo = coll2.containsAll(coll);//true 包含
//输出返回值
System.out.println(boo);
}
}
说明:
1)boolean removeAll(Collection c) :表示从调用这个函数执行的集合中删除当前集合与指定集合中共同的元素,删除交集;
2)boolean retainAll(Collection c) :表示从调用这个函数执行的集合中删除两个集合中不同的元素,也可以理解为保留两个集合中共有的元素,保留交集。
分析和步骤:
1)使用new关键字创建集合类ArrayList的两个对象coll和coll2,两个对象的类型是接口Collection;
2)使用coll和coll2对象分别调用add()函数给集合添加数据;
3)使用coll对象分别调用 removeAll()和retainAll()函数,coll2集合对象作为该函数的参数,最后输出布尔类型的返回结果和两个集合对象coll和coll2;
public static void method_3() {
// 创建集合对象
Collection coll = new ArrayList();
Collection coll2 = new ArrayList();
coll.add("aaaa");
coll.add("bvvv");
coll.add("dddd");
coll2.add("aaaa");
coll2.add("dddd2");
/*
* coll.removeAll(coll2)
* 是从coll集合中删除 coll与 coll2中相同的元素(交集)
*/
/*
boolean b = coll.removeAll(coll2);
System.out.println(coll);
System.out.println(coll2);
System.out.println(b);
*/
/*
* coll.retainAll(coll2)
* 是从coll中删除 coll与 coll2中不同的元素,也可以理解成保留2个集合的交集
*/
boolean b = coll.retainAll(coll2);
System.out.println(coll);
System.out.println(coll2);
System.out.println(b);
}
2.2.6 toArray()遍历集合
遍历就是指依次从容器中获取每一个容器中的对象元素。
问题1:我们之前直接通过输出集合的对象名比如:System.out.println(coll);就可以输出集合中的数据了,为什么还要遍历集合呢?
我们之前通过输出集合名的方式来输出集合中的数据的方法是可以将集合中的数据输出来,但是那些输出的都是将集合中的对象变成字符串然后拼接在一起输出的,这样输出就改变了原来对象的意思了,我们希望当时存储到集合中是对象,取出来的时候仍然是对象,这样不改变原来对象元素的意思,可以使用对象操作对象本身的函数或者属性。
问题2:现在会使用集合中的专用遍历方式吗?
不会。只会对数组进行遍历
在Collection集合中存在一个方法,可以把集合对象转为数组对象:
案例:对集合中的学生对象,进行遍历(集合转数组的方式实现)
分析和步骤:
1)定义一个Student类,在这个类中定义两个属性name和age;
2)在这个类中生成toString()函数,对外提供get和set方法;
3)在定义一个类,在这个类中创建集合对象stus;
4)使用集合对象stus调用add()函数向集合中添加学生对象;
5)使用集合对象stus调用toArray()函数将集合转换为数组;
6)使用for循环遍历数组,并根据数组名和下标输出对象即可;
/*
* 遍历集合
*/
public class CollectionToArrayDemo {
public static void main(String[] args) {
//创建集合对象
Collection coll=new ArrayList();
//创建学生对象
Student s=new Student("张三",18);
Student s1=new Student("李四",19);
Student s2=new Student("王五",20);
Student s3=new Student("老郭",21);
//将学生对象添加到集合中
coll.add(s);
coll.add(s1);
coll.add(s2);
coll.add(s3);
/*
* 想要对集合进行遍历我们还没有学习,但是我们学习过怎样对数组进行遍历
* 所以我们可以将集合转换为数组
*/
/*
int[] arr1={1,2,3};
int x=arr1[0];
String[] arr2={"ss","dd"};
String str=arr2[0];
*/
Object[] arr = coll.toArray();
//遍历数组
for (int i = 0; i < arr.length; i++) {
//取出数组中的对象数据
Object obj=arr[i];
//转换为Student类型
Student stu=(Student)obj;
//打印Student类中的属性值
// System.out.println(stu.getName()+"======"+stu.getAge());
/*
* 由于以上发生多态,但是子类Student类中有非静态成员函数toString(),所以根据多态的特 点,
* 对于非静态函数,如果子类有优先使用子类中的函数
*/
System.out.println(obj.toString());
}
}
}
2.3 迭代器(遍历器)Iterator
2.3.1、迭代器介绍
由于集合框架中的集合容器太多,而每个集合容器中保存的数据存储的方式都不一样。于是导致我们往出取数据的时候方式也完全不相同。
Java针对这些所有集合容器取出数据的方式进行共性的抽取,于是针对所有的集合定义了一个接口,在这个接口中描述了所有集合容器的共性遍历规则。
注意:对于集合取元素,无论是什么数据结构,最终共性的取出方式:
一个一个取,取之前先判断,有,取一个,没有,结束。
这种取出的共性方式:迭代。迭代可以理解为取出或者遍历。
而这个接口它就是Iterator,它中定义了集合最基本的遍历方式:
Iterator接口的迭代(取出、遍历)方式:
针对一个集合,需要遍历的时候,应该首先去判断集合中有没有元素(对象),有就取出这个元素,没有就不用再进行遍历了。
hasNext()函数表示判断容器中还有没有元素,如果有返回true,我们就可以根据这个返回的结果确定到底还要不要遍历这个集合容器
next()函数表示取出当前遍历到的那个元素。
void remove() 表示删除当前迭代器对象指向的集合中的元素。
对于迭代器Iterator中的函数解释和运行原理如下图所示:
说明:可以把迭代器对象理解成为一个移动的光标,开始的时候,光标会在集合容器的最上面,然后如果使用迭代器对象调用hasNext()函数的时候,光标会指向集合中第一个元素,如果hasNext()函数返回true,则说明有元素可以遍历(迭代),则使用迭代器对象调用next()函数就会将当前光标所指向的元素取出来,如果调用remove()函数,就会删除当前光标所指向的元素。
每执行完一次next()函数,光标都会往下移动,直到移动到集合的最低端,找不到元素为止。移动到最底端代表着此迭代器对象也使用完毕。
如果还想再重新迭代该集合那么需要再根据此集合重新创建一个迭代器对象。
注意:在使用集合对象生成迭代器对象后,那么此时这个迭代器对象已经记录下来此时集合中的结构,在使用迭代器遍历的时候, 一定记住不能使用集合的对象来对集合中的元素进行删除或者添加,如果要改动可以使用迭代器对象改动集合,如果要改动集合中的内容可以根据改动后的集合对象再重新生成迭代器对象。
下面就给一个demo方便去理解这个迭代器的具体使用:
说明:由于集合种类有很多,各不相同,所以迭代器对象也会有很多,针对不同集合获得不同的迭代器对象,但是最后使用迭代器对象调用Iterator迭代器中的函数实现的效果是一致的,没有区别,即:
根据迭代器对象调用hasNext()函数查看集合容器中是否含有要遍历的元素,调用next()函数获取集合容器中的元素。
步骤:
1)使用new关键字创建集合类ArrayList的对象coll,对象的类型是接口Collection;
2)使用对象coll调用add()函数给集合添加数据;
3)以前我们都是根据集合对象名coll将集合中的数据一次性输出,而这里我们要先使用集合对象coll调用iterator()函数获得迭代器对象;
4)然后根据迭代器对象调用next()函数依次取出数据并输出;
5)如果多次调用next()函数有可能会发生异常,因为集合中的数据已经取完了,所以为了防止发生异常,我们在取数据之前使用hasNext()函数进行判断一下,没有数据就不用取数据了;
6)由于是多条语句,我们可以考略使用循环while或者for;
结果肯定是报错的啊,还用想吗???
分析异常的原因:
说明:当迭代器对象指向集合时,可以获取集合中的元素,如果迭代器的光标移动集合的外边时,此时迭代器对象不再指向集合中的任何元素,会报NoSuchElementException没有这个元素异常。
这个其实就已经映射了帮助手册的方法了。
解决方案:
在使用next()函数获取集合中元素前,使用hasNext()判断集合中是否还有元素。
上述代码一条语句重复执行多次,我们可以考虑使用循环来控制执行的次数,
循环条件是 迭代器对象.hasNext() 为false时表示集合中没有元素可以获取了,循环条件迭代器对象.hasNext() 为true的时候说明还可以获取元素。
/*
* 演示迭代器的使用
*/
public class IteratorDemo {
public static void main(String[] args) {
//创建集合对象
Collection coll=new ArrayList();
//向集合中添加数据
coll.add("aaaa");
coll.add("bbbb");
coll.add("cccc");
//根据当前集合获取迭代器对象
Iterator it = coll.iterator();
//取出数据
/*System.out.println(it.next());//it.next()表示获取迭代器对象指向集合中的数据
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());*/
//使用while循环遍历集合
while(it.hasNext())//it.hasNext()表示循环条件,如果为true,说明集合中还有元素可以获取,否则没有元素
{
//获取元素并输出
System.out.println(it.next());
}
/*
* 注意:针对集合每次获取到的迭代器对象,使用完之后,迭代器中的隐式光标就已经到了集合的最后,这样就
无法再去使用next获取集合中的元素。如果还要获取,需要重新在获取一个迭代器对象。
*/
//报找不到元素异常,对于it迭代器对象,它已经移动到集合中最后了,再找就没有元素了,只能重新获得迭代器对象
//System.out.println(it.next());
//使用for循环遍历集合 推荐开发使用
/*for (Iterator it2 = coll.iterator(); it2.hasNext();) {
System.out.println(it2.next());
}*/
}
}
注意:针对集合每次获取到的迭代器对象,使用完之后,迭代器中的隐式光标就已经到了集合的最后,这样就
无法再去使用next获取集合中的元素。如果还要获取,需要重新在获取一个迭代器对象。
Q:while循环的迭代和for循环的迭代有什么不同?
A:while
循环的迭代,由于初始化迭代器对象在while循环上面,在整个while循环结束后,迭代器对象还可以继续使用,但是集合中已经没有数据了,如果还仍然使用迭代器对象继续获取数据,会报异常,如果还要获取,需要重新在获取一个迭代器对象。所以对于while循环当迭代器对象使用完之后,迭代器就会变成一个没有用的垃圾,占内存。
对于for循环的迭代,由于初始化迭代器对象在for循环小括号中,在整个for循环结束后,迭代器对象就不能继续使用,也不会占内存,所以建议大家以后在开发中使用迭代器遍历集合最好使用for循环。
不要问问什么,被吊多了你就知道了!
在开发中,建议大家使用迭代器遍历集合的时候最好使用for循环。
2.3.3迭代器注意细节
需求:遍历集合,遇到"abc"就把它删除。
解决方法:
1)使用new关键字创建集合类ArrayList的对象coll,对象的类型是接口Collection;
2)使用集合对象coll调用add()函数给集合中添加数据;
3)使用for循环遍历集合,取出每个元素,进行判断,只要当前取出的这个元素是"abc",就把它从集合中删除;
4)在for循环的初始化值位置上使用集合对象coll获取迭代器对象;
5)使用迭代器中的next()函数获取数据赋值给Object类型;
6)使用判断结构对取出的数据和字符串”abc”进行判断,如果找到,则使用迭代器对象调用迭代器中的remove()函数进行删除,不要使用集合中的remove(obj)函数,否则会报异常;
/*
* 需求:遍历集合,遇到"abc"就把它删除。
*/
public class IteratorDemo2 {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc");
coll.add("bbbbb");
coll.add("dddd");
coll.add("xyz");
coll.add("ABC");
/*
* 遍历集合,取出每个元素,进行判断,只要当前取出的这个元素是"abc"
* 就把它从集合中删除
*/
for( Iterator it = coll.iterator(); it.hasNext() ; ){
//取出这个元素进行判断
Object obj = it.next();
if( obj.equals("abc") ){
/*
* 当我们使用迭代器对集合中的元素进行迭代的时候,不允许使用集合自身的增删函数
* 对集合中的元素进行操作。 如果真的需要删除,这时只能使用迭代器自身的remove方法
*/
//coll.remove(obj);
it.remove();
}
}
System.out.println(coll);
}
}
说明:如果使用集合中的remove(obj)函数进行删除,为什么会报异常?
由于迭代器对象是基于集合而来的,如果已经获取到了迭代器对象,就可以使用迭代器对象遍历集合,而此时在遍历集合的时候,如果使用集合对象调用集合中的函数对集合进行增删操作,那么对于迭代器对象而言就会导致最开始生成迭代器对象和修改集合之后不一样,而在java中是不允许这样操作的,如果想要在迭代集合的时候删除集合中的元素可以使用迭代器Iterator中的remove()函数。
总结:
- 使用迭代器对集合进行迭代的时候,不要使用集合自身的功能(函数)对集合进行增删操作;
- 所有的迭代器当迭代结束之后,那么这个迭代器对象(隐式光标)就位于集合的最后;
- 使用迭代器迭代集合的时候,每一个hasNext()方法都对应一个next()函数,不要一个hasNext()方法对应多个next()函数。
如下图所示,就是一个hasNext()函数对应多个next()函数,使用是错误的。
- 可以使用增强for循环遍历集合更加简单一些;
但是使用增强for循环的时候需要注意集合中的数据类型是Object,因为集合中可以存储各种引用类型数据,而Object类是所有引用类型数据的父类。
3 使用集合的一些套路
1)集合中正常情况下是不能存储基本类型数据,
但是在JDK1.5后可以直接在add方法中书写基本类型数据,因为底层在操作时会对基本类型数据进行装箱。
2)集合中存储的任何类型的元素,在存储到集合中时,全部都会转为Object类型;
3)从集合中取出元素时,取出的元素类型全部都是Object类型,如果想要使用类中特有的成员时,需要向下转型;
例如上述存储在集合中的自定义Student类,想要使用Student类中的特有的get和set函数:
public class IteratorDemo1 {
public static void main(String[] args) {
//创建集合类对象
Collection coll=new ArrayList();
//向集合中添加数据
coll.add(new Student("张三",19));
coll.add("aaaa");
//遍历取出集合中的数据
for (Iterator it = coll.iterator(); it.hasNext();) {
Object obj = it.next();
/*
* 想通过取出的对象调用Student类中特有的getName()和getAge()函数获得属性值
* 由于getName()和getAge()函数是Student类中的特有的函数,而从集合中取出的数据
* 都是Object类型,要想使用子类Student特有的函数,必须向下转型,向下转型有风险
* 使用需谨慎,使用instanceof判断转型的数据类型
*/
if(obj instanceof Student)
{
//说明是Student类型
Student stu=(Student)obj;
System.out.println(stu.getName()+"====="+stu.getAge());
}
}
}
}
4)集合容器是用来保存对象的。而真正给集合中保存的不是当前那个对象,而是对象在堆内存中的内存地址。
给集合中保存自定义对象:
a.使用上述自定义的Student类,在类中定义name和age属性,生成get和set方法;
b.随便定义一个测试类,在main函数中创建集合对象,同时创建Student类的对象;
c.将Student类的对象添加到集合中,并迭代集合,遍历输出结果,会发现打印的是Student类的对象的地址值
d.如果在Student类中复写toString()函数就会打印name和age的属性值;
public static void main(String[] args) {
//创建集合类对象
Collection coll=new ArrayList();
//向集合中添加数据
coll.add(new Student("张三",19));
//遍历取出集合中的数据
for (Iterator it = coll.iterator(); it.hasNext();) {
/*
* 如果自定义Student类中不复写toString()函数那么就会输出一串内存地址
* cn.edu.kum.demo.Student@6d9dd520
*/
System.out.println(it.next());
}
}
}
集合的使用套路:
1、创建集合
2、添加元素
3、遍历集合:
1)获取迭代器对象;
2)循环迭代集合;