一、List和Set比较
1、List
(1)有序(存入和取出的顺序一致)
(2)元素都有索引(角标)
(3)元素可以重复
2、Set
(1)无序(有可能会有序,但几率不高)
(2)元素不能重复
List和Set最严重的区别在于:是否有重复元素
二、List
1、有序的collection。此接口的用户可以对列表中每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素
2、List特有的常见方法,都有一个共性特点:都可以操作角标 -- List最大的特点。即 凡是可以操作角标的,都是List的特有方法
3、只有List集合可以实现对元素的增删改查(Collection不具备修改功能)
4、方法(凡是参数为角标的方法,返回值多为对象E)
(1)迭代器
Iterator<E> iterator():返回按适当顺序在列表的元素上进行迭代的迭代器
ListIterator<E> listIterator():返回此列表元素的列表迭代器(按适当顺序)
ListIterator<E> listIterator(int index):返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。指定的索引表示next()的初始调用所返回的第一个元素
(2)添加
void add(int index, E element):在列表的指定位置插入指定元素
boolean addAll(int index, Collection<? extends E> c):将指定集合c中的所有元素都插入到列表中的指定位置
boolean add(E e):向列表的尾部添加指定的元素
boolean addAll(Collection<? extends E> c):将指定集合c中的所有元素添加到此列表的结尾
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
System.out.println(list); //[abc1, abc2]
//新插入的元素在角标1的位置上
list.add(1, "abc3");
System.out.println(list); //[abc1, abc3, abc2]
(3)删除
E remove(int index):移除列表中指定位置的元素,返回被移除的元素
boolean remove(Object o):从此列表中移除第一次出现的指定元素(如果存在)
boolean removeAll(Collection<?> c):移除collection中也包含在指定集合c中的所有元素
void clear():从列表中移除所有元素。此调用返回后该列表将是空的
注:参数为对象的删除方法,不返回对象,因为删除的对象是指定好的(已知)。参数为角标的删除方法,会返回被删除的对象,因为指定角标对应的是哪个对象并不知道
(4)修改
E set(int index, E element):用指定元素替换列表中指定位置的元素,返回被替换的元素 -- 只有List有修改功能
(5)获取
E get(int index):返回列表中指定位置的元素
int indexOf(Object o):返回此列表中第一次出现的指定元素的索引
int lastIndexOf(Object o):返回此列表中最后出现的指定元素的索引
List<E> subList(int fromIndex, int toIndex):返回列表中指定的fromIndex和toIndex之间的部分视图(包含fromIndex,不包含toIndex)。eg:从列表中移除了元素的范围:list.subList(from, to).clear(); 具体说明见第5点
int size():返回列表中的元素数
(6)判断
boolean contains(Object o):如果列表包含指定的元素,则返回true
boolean containsAll(Collection<?> c):如果列表包含指定集合c的所有元素,则返回true
boolean isEmpty():如果列表不包含元素(列表为空),则返回true
(7)其他
boolean retainAll(Collection<?> c):仅在列表中保留指定集合c中也包含的元素(取交集)
Object[] toArray():返回按适当顺序包含列表中的所有元素的数组
5、List<E> subList(int fromIndex, int toIndex); 方法说明
(1)该方法返回的是父list的一个视图,从fromIndex(包含),到toIndex(不包含)。fromIndex = toIndex 表示子list为空
(2)对于非结构性修改,父子list做的非结构性修改都会影响到彼此
(3)对于结构性修改,子list的所有操作都会反映到父list上,但父list的修改将会导致返回的子list失效
注:非结构性修改:不涉及到list的大小改变的修改
List list = new ArrayList();
list.add("a");
//使用构造器创建一个包含list的列表list1
List list1 = new ArrayList(list);
//使用subList生成与list相同的列表list2
List list2 = list.subList(0, list.size());
//结构性修改(长度改变):子list的修改会影响到父list
list2.add("b");
System.out.println(list.equals(list1)); //false
System.out.println(list.equals(list2)); //true
List c = new ArrayList();
c.add("abc1");
c.add("abc2");
c.add("abc3");
c.add("abc4");
System.out.println(c); //[abc1, abc2, abc3, abc4]
List a = c.subList(1,3);
System.out.println(a); //[abc2, abc3]
System.out.println(c); //[abc1, abc2, abc3, abc4]
//结构性修改(长度改变):子list的修改会影响到父list
a.clear();
System.out.println(a); //[]
System.out.println(c); //[abc1, abc4]
//结构性修改(长度改变)):父list的修改会导致子list失效
c.add("text");
System.out.println(c); //[abc1, abc4, text]
// System.out.println(a); //报错,java.util.ConcurrentModificationException
List parentList = new ArrayList();
for (int i = 0; i < 5; i++) {
parentList.add(String.valueOf(i)); //parentList:[0, 1, 2, 3, 4]
}
List subList = parentList.subList(1, 3); //subList:[1, 2]
//子修改
//非结构性修改(长度不变):子list和父list相互影响
subList.set(0, "new 1"); //subList:[new 1, 2], parentList:[0, new 1, 2, 3, 4]
//结构性修改(长度改变):子list的修改会影响到父list
subList.add(String.valueOf(2.5)); //subList:[new 1, 2, 2.5], parentList:[0, new 1, 2, 2.5, 3, 4]
//父修改
//非结构性修改(长度不变):父list和子list相互影响
parentList.set(2, "new 2"); //parentList:[0, new 1, new 2, 2.5, 3, 4], subList:[new 1, new 2, 2.5]
//结构性修改(长度改变):父list修改导致子list失效
parentList.add("undefine"); //parentList:[0, new 1, new 2, 2.5, 3, 4, undefine], subList:报错,java.util.ConcurrentModificationException
三、ListIterator
1、interface ListIterator<E> extends Iterator<E>:可以按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置
2、ListIterator是List特有的迭代器(列表迭代器)
3、方法
(1)void add(E e):将指定的元素插入列表。该元素直接插入到next()返回的下一个元素的前面,或者previous()返回的下一个元素之后
(2)boolean hasNext():以正向遍历列表时,如果列表迭代器有多个元素,则返回true
(3)boolean hasPrevious():如果以逆向遍历列表,列表迭代器有多个元素,则返回true
(4)E next():返回列表中的下一个元素。可以重复调用此方法来迭代此列表
(5)int nextIndex():返回对next()的后续调用所返回元素的索引
(6)E previous():返回列表中的前一个元素。可以重复调用此方法来迭代列表
(7)int previousIndex():返回对previous()的后续调用所返回元素的索引
(8)void remove():从列表中移除由next()或previous()返回的最后一个元素。对于每个next()或previous()调用,只能执行一次此调用
(9)void set(E e):用指定元素替换next()或previous()返回的最后一个元素
注:正向遍历的指针是从第一个元素的左边开始,到最后一个元素结束;逆向遍历的指针是从最后一个元素的右边开始,到第一个元素结束
4、只有列表迭代器ListIterator可在迭代过程中对元素进行增删改查操作
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
Iterator it = list.iterator();
while (it.hasNext()) {
//用Object类型接收是因为:public boolean add(Object obj);,添加的是Object类型的元素(向上转型),向外取出时也要用Object接收
Object obj = it.next(); //java.util.ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出异常
if (obj.equals("abc2")) {
//引发异常的语句。迭代器拿到集合中元素的个数为2个,而集合add的新元素,迭代器并不知道。即 集合和迭代器同时对元素进行修改,就会导致迭代出问题
list.add("abc3");
}
}
/**
* 思考:
*
* 问题:迭代器和集合同时访问造成并发,抛出异常
* 如何避免问题:使用集合操作时不迭代,使用迭代操作时不集合操作,不冲突即可
* 解决:在迭代过程中不用集合操作(list.add()),就只能用迭代操作(迭代进行集合中元素的增删改查)
*
* 迭代器操作
* 问题:Iterator只有 hasNext()、next()、remove()三个方法,没有添加和修改
* 解决:可以使用Iterator的子接口:ListIterator(列表迭代器)
* ListIterator的好处:可以在迭代过程中对元素进行增删改查
*/
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
//列表迭代器ListIterator,此迭代器只有List有 (只有ListIterator可以实现在迭代过程中对元素的增删改查)
ListIterator it = list.listIterator();
while (it.hasNext()) {
//用Object类型接收是因为:public boolean add(Object obj);,添加的是Object类型的元素(向上转型),向外取出时也要用Object接收
Object obj = it.next();
if (obj.equals("abc2")) {
//调用迭代器的方法进行增删改查,而不是集合的
//下面语句一次只能打开一个
// it.add("abc3"); //[abc1, abc2, abc3]。加在“abc2”后面
// it.set("abc4"); //[abc1, abc4]。将“abc2”换成“abc4”
}
}
System.out.println(list);
四、List取出元素的方式(三种)
1、iterator():迭代器。通用,Collection的子类都具备
2、listIterator():迭代器。List特有
3、get(int index):根据角标获取元素。List特有
List list = new ArrayList();
list.add("abc");
/**
* List有三种取出元素的方式,后两种是List特有的
*/
/**
* 方法一:iterator(),通用 -- Collection的子类都具备
*/
// Iterator it = list.iterator();
// while (it.hasNext()){
// it.next();
// }
/**
* 方法二:listIterator(),List特有
*/
ListIterator it = list.listIterator();
while (it.hasNext()) {
it.next();
}
/**
* 方法三:get(),List特有
*/
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
五、List特有的内容(只有List有)
(1)可以操作角标
(2)可以实现对元素的增删改查
(3)有列表迭代器ListIterator,可以在迭代过程中对元素进行增删改查