List接口概述:
List接口是Collection接口的子类
Collection中的常用子类(List集合、Set集合)。
List接口的用户可以对列表中每个元素的插入位置进行精确地控制。
用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
与 set 不同,列表通常允许重复的元素。
List接口的特点:
①它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
②它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
③集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
List接口的常用子类有:
①ArrayList集合
②LinkedList集合
List接口常用方法:
1、增加元素方法
①add(Object e):向集合末尾处,添加指定的元素
②add(int index, Object e):向集合指定索引处,添加指定的元素,原有元素依次后移
2、删除元素删除
①remove(Object e):将指定元素对象,从集合中删除,返回值为被删除的元素
②remove(int index):将指定索引处的元素,从集合中删除,返回值为被删除的元素
3、替换元素方法
set(int index, Object e):将指定索引处的元素,替换成指定的元素,返回值为替换前的元素
4、查询元素方法
get(int index):获取指定索引处的元素,并返回该元素
演示:
public class demo01 { public static void main(String[] args) { List<String> list=new ArrayList<String>(); list.add("You "); list.add("are "); list.add(2, "beautifal!"); //前提必须有这个下标 //list.set(3, "aaa");//下标越界异常 //删除(返回删除元素) String s=list.remove(1); System.out.println(s); for(String str:list){ System.out.print(str); } } }
Iterator并发修改异常
public class IteratorDemo { //在list集合迭代元素中,对元素进行判断,一旦条件满足就添加一个新元素 public static void main(String[] args) { //创建List集合 List<String> list = new ArrayList<String>(); //给集合中添加元素 list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); //迭代集合,当有元素为"abc2"时,集合加入新元素"itcast" Iterator<String> it = list.iterator(); while(it.hasNext()){ String str = it.next(); //判断取出的元素是否是"abc2",是就添加一个新元素 if("abc2".equals(str)){ list.remove(0); /** * 直接运行 * list.add("itcast"); * 运行到add的时候出现“并发修改异常”, * 导致迭代器并不知道集合中的变化,容易引发数据的不确定性。 * Exception in thread "main" java.util.ConcurrentModificationException */ if(list.add("itcast")){ break;//添加成功以后直接break;不继续判断就可以不出现异常 } } } //打印容器中的元素 System.out.println(list); } }
总结:在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。
解决方法:在迭代时,不要使用集合的方法操作元素。
那么想要在迭代时对元素操作咋办?
通过ListIterator迭代器操作元素是可以的,ListIterator的出现,解决了使用Iterator迭代过程中可能会发生的错误情况。
或者像上方那样break。但是不能循环所有元素
public class IteratorDemo2 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); ListIterator<String> listit=list.listIterator(); while(listit.hasNext()){ if(listit.next().equals("b")){ /** * ListIterator有add和remove方法,可以向List中添加对象 */ listit.remove(); listit.add("itcast"); } } // Iterator<String> it=list.iterator(); // while(it.hasNext()){ // if(it.next().equals("b")){ // list.remove(0); // if(list.add("itcast")){ // break;//添加成功以后直接break;不继续判断就可以躲过异常 // } // } // } System.out.println(list); } }
一.相同点
都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用。
二.不同点
1.使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。
2.ListIterator有add方法,可以向List中添加对象,而Iterator不能。
3.ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)
遍历。Iterator不可以。
4.ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
5.都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。
List集合存储数据的结构
数据存储的常用结构有:堆栈、队列、数组、链表。
1、堆栈,采用该结构的集合,对元素的存取有如下的特点:
①先进后出(即,存进去的元素,要在它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上
面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。
②栈的入口、出口的都是栈的顶端位置
③压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
④弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。
2、队列,采用该结构的集合,对元素的存取有如下的特点:
①先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,安检。排成一列,每个人依次检查,只有前面的人全部检查完毕后,才能
排到当前的人进行检查。
②队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口。
3、数组,采用该结构的集合,对元素的存取有如下的特点:
①查找元素快:通过索引,可以快速访问指定位置的元素
②增删元素慢:
指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。如下图
指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。
4、链表,采用该结构的集合,对元素的存取有如下的特点:
①多个节点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了。
②查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
③增删元素快:
增加元素:操作如左图,只需要修改连接下个元素的地址即可。
删除元素:操作如右图,只需要修改连接下个元素的地址即可。
ArrayList集合
ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。
LinkedList集合
LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。
LinkedList<String> link = new LinkedList<String>(); //添加元素 link.addFirst("abc1"); link.addFirst("abc2"); link.addFirst("abc3"); //获取元素 System.out.println(link.getFirst()); System.out.println(link.getLast()); //删除元素 System.out.println(link.removeFirst()); System.out.println(link.removeLast()); while(!link.isEmpty()){ //判断集合是否为空 System.out.println(link.pop()); //弹出集合中的栈顶元素 }