系列文章目录

文章目录

  • ​​系列文章目录​​
  • ​​前言​​
  • ​​一、Collection系列的集合的遍历是什么?​​
  • ​​二、java.util.Iterator:接口​​
  • ​​三、 java.util.Iterator:迭代器接口​​
  • ​​完整代码​​
  • ​​MyArrayList类代码:​​

前言

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java


接上一篇

需要注意的是我们目前所讲的是Collection系列的集合,先不讲Map

一、Collection系列的集合的遍历是什么?

Collection系列的集合的遍历:挨个访问集合的元素

(1)Object[] toArray():先返回数组,然后遍历数组

(2)迭代器设计模式

每一个Collection系列的集合,内部都自带一个迭代器,类似于,每一趟公交车上都有自己的售票员

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java_02

二、java.util.Iterator:接口

它是所有售票员的标准接口(就像生活中的售票员,检查每个人有没有票,到地点请乘客下次等等)

(1)判断是否还有下一个元素:hasNext()

(2)访问它的下一个元素:next()

(3)请下一个元素下车:remove()

遍历方式一:

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_Collection_03


00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_Collection_04


错误写法示范

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_System_05


正确写法:

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java_06


或者如下

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java_07


那么它跟集合有什么区别呢,如果我们不用这种方式删除,用另外一种方式会怎么样,想一下集合能不能删掉?

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_Collection_08


答案是,不能,因为它不能像上面那样加条件去删除

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java_09


这也就是迭代器的作用,可以根据某种条件去进行删除等操作

那么 java.util.Iterator迭代器接口 它既然是接口,那么是在哪里实现的呢?

三、 java.util.Iterator:迭代器接口

这个接口的实现类在每一种集合类中,例如:ArrayList内部有一个内部类实现了Iterator接口

这里声明为内部类有两个原因:

(1)每一种集合的内部实现(物理结构不同),意味着对迭代器(售票员)的实现是不同的,每一种集合都要单独定制迭代器

(2)内部类可以直接访问外部类的私有的属性,成员,迭代器就可以直接访问集合的私有的元素。

(3)foreach:增强for循环

foreach循环可以用于遍历数组、Collection系列的集合等容器。

语法结构:

for(元素的类型 元素临时名称 : 数组和集合名){

}

遍历方式2:

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java_10


注意它是不同于普通for循环的

for(int i=0; i<5; i++){

}

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_迭代器_11


什么样集合或容器类型可以使用foreach循环?

凡是实现了java.lang.Iterable接口(可迭代)的集合或容器都支持foreach循环

foreach底层还是调用Iterator迭代器来遍历集合。

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_Collection_12


00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_System_13


有抽象方法那就重写一下

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_System_14


那就继续写迭代器

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_迭代器_15


00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_java_16

为什么只有两个抽象方法,我们打开源码看一下,原来是因为remove不是抽象方法,而是默认方法

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_System_17


00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_Collection_18


回到调用的地方

00019.05 Collection集合遍历的几种方式(包含迭代器的作用)_System_19


遍历了四次,这可以说明, foreach底层还是调用Iterator迭代器来遍历集合,只是写法有点不同而已

完整代码

package com.atguigu.test05;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.junit.Test;

/*
* Collection系列的集合的遍历:挨个访问集合的元素
* (1)Object[] toArray():先返回数组,然后遍历数组
* (2)迭代器设计模式
* 每一个Collection系列的集合,内部都自带一个迭代器,类似于,每一趟公交车上都有自己的售票员
*
* java.util.Iterator:接口
* 它是所有售票员的标准接口。
* (1)判断是否还有下一个元素:hasNext()
* (2)访问它的下一个元素:next()
* (3)请下一个元素下车:remove()
*
* java.util.Iterator:迭代器接口,这个接口的实现类在每一种集合类中,例如:ArrayList内部有一个内部类实现了Iterator接口
* 这里声明为内部类有两个原因:
* (1)每一种集合的内部实现(物理结构不同),意味着对迭代器(售票员)的实现是不同的,每一种集合都要单独定制迭代器
* (2)内部类可以直接访问外部类的私有的属性,成员,迭代器就可以直接访问集合的私有的元素。
* (3)foreach:增强for循环
* foreach循环可以用于遍历数组、Collection系列的集合等容器。
* 语法结构:
* for(元素的类型 元素临时名称 : 数组和集合名){
*
* }
*
* 不同于普通for循环。
* for(int i=0; i<5; i++){
* }
*
* 什么样集合或容器类型可以使用foreach循环?
* 凡是实现了java.lang.Iterable接口(可迭代)的集合或容器都支持foreach循环
*
* foreach底层还是调用Iterator迭代器来遍历集合。
*/
public class TestIterator {
@SuppressWarnings("all")
@Test
public void test5(){
//我自己写的动态数组
MyArrayList list = new MyArrayList();
list.add("张三");
list.add("李四");
list.add("王五");

for (Object obj : list) {
System.out.println(obj);
}
}

@SuppressWarnings("all")
@Test
public void test4(){
String[] arr = {"hello","world","java"};
for (String string : arr) {
System.out.println(string);
}
}

@SuppressWarnings("all")
@Test
public void test3(){
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");

//Object:元素的数据类型
//obj:临时的元素名称
//c:要遍历的集合的名称
for (Object obj : c) {
System.out.println(obj);
}
}

@SuppressWarnings("all")
@Test
public void test2(){
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");

//返回这个集合自带的迭代器对象,相当于你找到了售票员
//让售票员去挨个的访问元素
Iterator iterator = c.iterator();
while(iterator.hasNext()){
String obj = (String) iterator.next();
//要姓“王”下车
if(obj.startsWith("王")){
iterator.remove();
}
}

System.out.println(c);
}


@SuppressWarnings("all")
@Test
public void test1(){
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");

//返回这个集合自带的迭代器对象,相当于你找到了售票员
//让售票员去挨个的访问元素
Iterator iterator = c.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}
}

MyArrayList类代码:

package com.atguigu.test05;

import java.util.Arrays;
import java.util.Iterator;

/*
* MyArrayList我们自己设计的一种数据结构,一种逻辑结构,当别人用我这个MyArrayList的对象时,就是一个容器对象,
* 可以用来装对象。
*/
public class MyArrayList implements Iterable{
//为什么使用Object,因为只是说这个容器是用来装对象的,但是不知道用来装什么对象。
private Object[] data;
private int total;

public MyArrayList(){
data = new Object[5];
}

//添加一个元素
public void add(Object obj){
//检查是否需要扩容
checkCapacity();
data[total++] = obj;
}

private void checkCapacity() {
//如果data满了,就扩容为原来的2倍
if(total >= data.length){
data = Arrays.copyOf(data, data.length*2);
}
}

//返回实际元素的个数
public int size(){
return total;
}

//返回数组的实际容量
public int capacity(){
return data.length;
}

//获取[index]位置的元素
public Object get(int index){
//校验index的合理性范围
checkIndex(index);
return data[index];
}

private void checkIndex(int index) {
if(index<0 || index>=total){
throw new RuntimeException(index+"对应位置的元素不存在");
// throw new IndexOutOfBoundsException(index+"越界");
}
}

//替换[index]位置的元素
public void set(int index, Object value){
//校验index的合理性范围
checkIndex(index);

data[index] = value;
}

//在[index]位置插入一个元素value
public void insert(int index, Object value){
/*
* (1)考虑下标的合理性
* (2)总长度是否够
* (3)[index]以及后面的元素往后移动,把[index]位置腾出来
* (4)data[index]=value 放入新元素
* (5)total++ 有效元素的个数增加
*/

//(1)考虑下标的合理性:校验index的合理性范围
checkIndex(index);

//(2)总长度是否够:检查是否需要扩容
checkCapacity();

//(3)[index]以及后面的元素往后移动,把[index]位置腾出来
/*
* 假设total = 5, data.length= 10, index= 1
* 有效元素的下标[0,4]
* 移动:[1]->[2],[2]->[3],[3]->[4],[4]->[5]
* 移动元素的个数:total-index
*/
System.arraycopy(data, index, data, index+1, total-index);

//(4)data[index]=value 放入新元素
data[index] = value;

//(5)total++ 有效元素的个数增加
total++;
}

//返回所有实际存储的元素
public Object[] getAll(){
//返回total个
return Arrays.copyOf(data, total);
}

//删除[index]位置的元素
public void remove(int index){
/*
* (1)校验index的合理性范围
* (2)移动元素,把[index+1]以及后面的元素往前移动
* (3)把data[total-1]=null 让垃圾回收器尽快回收
* (4)总元素个数减少 total--
*/

//(1)考虑下标的合理性:校验index的合理性范围
checkIndex(index);

//(2)移动元素,把[index+1]以及后面的元素往前移动
/*
* 假设total=8, data.length=10, index = 3
* 有效元素的范围[0,7]
* 移动:[4]->[3],[5]->[4],[6]->[5],[7]->[6]
* 移动了4个:total-index-1
*/
System.arraycopy(data, index+1, data, index, total-index-1);

//(3)把data[total-1]=null 让垃圾回收器尽快回收
data[total-1] = null;

// (4)总元素个数减少 total--
total--;
}

//查询某个元素的下标
/* public int indexOf(Object obj){
for (int i = 0; i < total; i++) {
//这两种写法都有风险
if(obj.equals(data[i])){
//if(data[i].equals(obj)){
return i;//找到,返回第一个找到的
}
}
return -1;//没找到返回-1
}*/

//查询某个元素的下标
public int indexOf(Object obj){
if(obj == null){
for (int i = 0; i < total; i++) {
if(data[i] == null){//等价于 if(data[i] == obj)
return i;
}
}
}else{
for (int i = 0; i < data.length; i++) {
if(obj.equals(data[i])){
return i;
}
}
}
return -1;
}

//删除数组中的某个元素
//如果有重复的,只删除第一个
public void remove(Object obj){
/*
* (1)先查询obj的[index]
* (2)如果存在,就调用remove(index)删除就可以
*/

//(1)先查询obj的[index]
int index = indexOf(obj);

if(index != -1){
remove(index);
}
//不存在,可以什么也不做
//不存在,也可以抛异常
//throw new RuntimeException(obj + "不存在");
}

public void set(Object old, Object value){
/*
* (1)查询old的[index]
* (2)如果存在,就调用set(index, value)
*/

// (1)查询old的[index]
int index = indexOf(old);
if(index!=-1){
set(index, value);
}

//不存在,可以什么也不做
//不存在,也可以抛异常
//throw new RuntimeException(old + "不存在");
}

@Override
public Iterator iterator() {
return new MyItr();
}

private class MyItr implements Iterator{
private int cursor;//游标

@Override
public boolean hasNext() {
System.out.println("还有下一个");
return cursor!=total;
}

@Override
public Object next() {
System.out.println("拿到下一个");
return data[cursor++];
}

}
}