Collection子接口:List
【Java基础】集合框架
【Java基础】Collection子接口:List
【Java基础】List接口的子类
List接口
List接口:有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 set 不同,列表通常允许重复的元素。
List接口框架
|---Collection接口:单列集合,用来存储一个一个的对象;
|---List接口:存储有序的、可重复的数据; -->“动态”数组,替换原有的数组
|---ArrayList:作为List接口的主要实现类;线程不安全的,效率高;
底层使用Object[] elementData存储;
|---LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;
底层使用双向链表存储;
|---Vector:作为List接口的古老实现类;线程安全的,效率低;
底层使用Object[] elementData存储;
List的特有功能
(1)添加功能
void add(int index,Object element)
(2)获取功能
Object get(int index)
(3)列表迭代器
ListIterator listIterator()
(4)删除功能
Object remove(int index)
(5)修改功能
Object set(int index,Object element)
列表迭代器 ListIterator
- ListIterator listIterator():List集合特有的迭代器;
- 该迭代器继承了Iterator迭代器,可以直接使用hasNext()和next()方法;
- 用于允许程序员沿任一方向遍历的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置;
ListIterator的特有功能
- Object previous():获取上一个元素
- boolean hasPrevious():判断是否有元素
ListIterator<String> lit = list.listIterator();
//正向遍历
while (lit.hasNext()) {
String s = lit.next();
System.out.println(s);
}
//逆向遍历
while (lit.hasPrevious()) {
String s = lit.previous();
System.out.println(s);
}
注意:ListIterator可以实现逆向遍历,但是必须先正向遍历,才能逆向遍历,所以一般无意义不使用;
并发修改异常
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常:ConcurrentModificationException;
现象
eg:判断一个集合里面是否有"world"这个元素,如果有就添加一个"javaee"元素;
//错误写法,运行会报错
//ConcurrentModificationException
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListIterator {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList();
//创建字符串对象
//把字符串添加到集合
list.add("hello");
list.add("world");
list.add("java");
System.out.println("list:" + list);
//list:[hello, world, java]
//迭代器遍历
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("world".equals(s)) {
list.add("javaee");
}
}
System.out.println("list:" + list);
//ConcurrentModificationException
}
}
//迭代器遍历元素的时候,不能通过集合对象修改元素;
产生的原因
迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际修改值不一致,则会出现并发修改修改异常;
解决方案
(1)ListIterator迭代器迭代元素,迭代器修改元素,元素是跟在刚才迭代的元素后面的;
//Iterator迭代器没有添加功能
//要使用其子接口ListIterator迭代器
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
String s = lit.next();
if ("world".equals(s)) {
lit.add("javaee");
}
}
System.out.println("list:" + list);
//list:[hello, world, javaee, java]
(2)集合遍历元素,集合修改元素(普通for),元素在最后添加的;
for (int x = 0; x < list.size(); x++) {
String s = list.get(x);
if ("world".equals(s)) {
list.add("javaee");
}
}
//list:[hello, world, java, javaee]
List集合的遍历
1、使用迭代器
1.1、Iterator迭代器
Iterator<String> it = list.iterator(); //返回的是实现类的对象
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
1.2、ListIterator迭代器
ListIterator<String> lit = list.listIterator(); //返回的是实现类的对象
while (lit.hasNext()) {
String s = lit.next();
System.out.println(s);
}
2、使用普通for
List集合的特有遍历功能:size()和get()方法结合使用
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
3、使用增强for
for (String s : list) {
System.out.println(s);
}
List集合的案例
1、存储字符串并遍历
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListDemo1 {
public static void main(String[] args) {
//创建集合对象
List<String> list = new ArrayList<String>();
//把字符串添加到集合
list.add("hello");
list.add("world");
list.add("java");
//遍历集合
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
String s = lit.next();
System.out.println(s);
}
}
}
2、存储自定义对象并遍历
//定义学生类Student-->省略
//测试类:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
class ListDemo2 {
public static void main(String[] args) {
//创建集合对象
List<Student> list = new ArrayList<Student>();
//创建学生对象
Student s1 = new Student("张三", 18);
Student s2 = new Student("李四", 20);
Student s3 = new Student("王五", 22);
Student s4 = new Student("赵六", 24);
//把学生添加到集合
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
//遍历集合
for (int x = 0; x < list.size(); x++) {
Student s = list.get(x);
System.out.println(s.getName() + "," + s.getAge());
}
}
}
List接口的子类
List接口的子类:ArrayList、LinkedList、Vector
面试题:List接口的子类的异同
- 相同点:
- 三个类都是实现了List接口
- 存储数据的特点相同:存储有序的、可重复的数据
- ArrayList:
- 底层数据结构是数组,查询快,增删慢;
- 线程不安全,效率高;
- Vector:
- 底层数据结构是数组,查询快,增删慢;
- 线程安全,效率低;
- LinkedList:
- 底层数据结构是链表,查询慢,增删快;
- 线程不安全,效率高;
开发时如何选用List接口的子类?
- 具体看需求,不知道用哪个就选ArrayList
- 要安全:Vector
- 不要安全:ArrayList 或 LinkedList
- 查询多:ArrayList
- 增删多:LinkedList