Iterator迭代器
迭代的概念
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
获取迭代器对象
Collection集合提供了一个获取迭代器的方法:
public Iterator iterator()`: 获取集合对应的迭代器,用来遍历集合中的元素的
Iterator接口的常用方法
- public E next()`:返回迭代的下一个元素。
public boolean hasNext()
:如果仍有元素可以迭代,则返回 true。
案例演示
public class Test {
public static void main(String[] args) {
/*
- 迭代的概念
概述: Collection集合获取元素通用的方式。在获取元素之前要先判断集合中是否有元素可以获取,如果有,
就把这个元素取出来,接下来继续判断,如果还有,就继续取出来,直到把集合中所有元素取出来为止,这就
是迭代
- 获取迭代器对象
1.迭代器对象:Iterator接口对象
2.如何获取集合对应的迭代器对象
使用Collection集合中的iterator()方法:
Iterator<E> iterator();获取集合对应的迭代器对象
- Iterator接口的常用方法
boolean hasNext() 判断集合中是否有元素可以迭代
E next() 获取集合中的元素
*/
// 创建一个Collection集合,限制集合中元素的类型为String
Collection<String> col = new ArrayList<>();
// 添加元素
col.add("范冰冰");
col.add("李冰冰");
col.add("高圆圆");
col.add("刘诗诗");
// 迭代
// 获取该集合对应的迭代器对象
Iterator<String> it = col.iterator();
// 使用while循环,判断集合中是否有元素可以获取
while (it.hasNext()) {
// 如果有,就取出来
String e = it.next();
System.out.println(e);
}
}
}
常见问题一
在进行集合元素获取时,如果集合中已经没有元素可以迭代了,还继续使用迭代器的next方法,将会抛出java.util.NoSuchElementException没有集合元素异常。
常见问题二
在进行集合元素迭代时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出ConcurrentModificationException并发修改异常.
迭代器的实现原理
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
增强for
是for循环中增强的方法,高级for循环,专门用来遍历数组和集合的,内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
格式:
for(元素的数据类型 变量 : Collection集合or数组){
//写操作代码
}
特别注意:
1.增强for循环必须有被遍历的目标,目标只能是Collection集合或者是数组,与Map双列集合无关;
2.Collection是所有单列集合的根接口,如果要对单列集合进行遍历,通用的遍历方式是迭代器遍历或增强for遍历。
3.增强for(迭代器)仅仅作为遍历操作出现,不能对集合进行增删元素操作,否则抛出ConcurrentModificationException并发修改异常
泛型
泛型的概述:
泛型是为了方便安全集合储存数据,控制未知数据类型而服务的
泛型的作用:
使用泛型在编译期直接对集合的数据类型做出了控制,指定储存的数据类型,如果不使用泛型,集合存进去什么类型都能存,取出来时啥也不是,报异常。
泛型通配符
泛型通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
通配符高级使用----受限泛型
泛型的上限:**
- 格式**:
类型名称 <? extends 类 > 对象名称
- 意义:
只能接收该类型及其子类
泛型的下限:* - 格式**:
类型名称 <? super 类 > 对象名称
- *意义:
只能接收该类型及其父类型
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement1(list1);
getElement1(list2);//报错
getElement1(list3);
getElement1(list4);//报错
getElement2(list1);//报错
getElement2(list2);//报错
getElement2(list3);
getElement2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
数据结构
数据结构 : **其实就是存储数据和表示数据的方式,常见的数据结构:堆栈、队列、数组、链表和红黑树 .
栈
栈**:stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在表的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作
例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。
注意:
1.栈先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)
2.栈的入口、出口的都是栈的顶端位置**。
3.压栈**:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
4.弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。
**
队列
队列**:queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行取出并删除。
对元素存取特点:
1.先进先出**(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。
2.队列的入口、出口各占一侧。**例如,下图中的左侧为入口,右侧为出口。
数组
数组**:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。
数组特点:
1.查询块
(通过索引,可以快速访问指定位置的元素)
2.增删慢
(1.增加需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置;
2.指定索引位置删除元素需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中)
数组特点六个字:查询块,增删慢。
链表
链表:由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表
二叉树
如果树中的每个节点的子节点的个数不超过2,那么该树就是一个二叉树。
二叉查找树
二叉查找树的特点:
- 左子树上所有的节点的值均小于等于他的根节点的值
- 右子树上所有的节点值均大于或者等于他的根节点的值
- 每一个子节点最多有两个子树
平衡二叉树
规则:**它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
红黑树
红黑树是一种自平衡的二叉查找树
红黑树的特性:
- 每一个节点或是红色的,或者是黑色的。
- 根节点必须是黑色
- 每个叶节点(Nil)是黑色的;(如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点)
- 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
- 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;