1.1 List集合特点、特有API
ArrayList、LinekdList :有序,可重复,有索引。
除了继承自Collection的方法,List集合拥有特有方法:
方法名称 | 说明 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
// List:有序,可重复,有索引的。
ArrayList<String> list = new ArrayList<>(); // 一行经典代码!
list.add("Java");
list.add("Java");
list.add("MySQL");
// 2.在某个索引位置插入元素。
list.add(2, "黑马");
// 3.根据索引删除元素,返回被删除元素
String s1 = list.remove(1);
// 4.修改索引位置处的元素,返回被修改的元素
String s1 = list.set(1, "传智教育");
// 5.根据索引获取元素:public E get(int index):返回集合中指定位置的元素。
String s1 = list.get(1);
List的实现类的底层原理:
- ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢。
- LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的。
1.2 List集合的遍历方式小结
①迭代器
②增强for循环
③Lambda表达式
④for循环(因为List集合存在索引)
1.3 ArrayList集合的底层原理(面试)
- ArrayList底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。
- 第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。
1.4 LinkedList集合的底层原理
特点:底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkedList集合的特有功能:
方法名称 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
// LinkedList可以完成队列结构,和栈结构 (双链表)
// 1、做一个队列:
LinkedList<String> queue = new LinkedList<>();
// 入队
queue.addLast("1号");
queue.addLast("2号");
// 出队
System.out.println(queue.removeFirst());
//返回队首元素
System.out.println(queue.peek());
// 2、做一个栈
LinkedList<String> stack = new LinkedList<>();
// 入栈 压栈 (push)
stack.push("第1颗子弹");
stack.push("第2颗子弹");
// 出栈 弹栈 pop
System.out.println(stack.pop());
//返回栈顶元素
System.out.println(stack.peek());
六、集合的并发修改异常问题
当我们遍历集合中找出某个元素同时删除的时候可能出现一种并发修改异常问题。(遍历删除过程中,指针指向的的位置的错误导致)
哪些遍历存在问题?
- 迭代器遍历集合且直接用集合删除元素的时候可能出现。
- 增强for循环遍历集合且直接用集合删除元素的时候可能出现。
// 1、准备数据
ArrayList<String> list = new ArrayList<>();
list.add("黑马");
list.add("Java");
list.add("Java");
list.add("素素");
// 需求:删除全部的Java信息。
// a、迭代器遍历删除
Iterator<String> it = list.iterator();
while (it.hasNext()){
String ele = it.next();
if("Java".equals(ele)){
// 删除Java
// list.remove(ele); // 集合删除会出毛病
it.remove(); // 删除迭代器所在位置的元素值(没毛病)
}
}
// b、foreach遍历删除 (会出现问题,这种无法解决的,foreach不能边遍历边删除,会出bug)
for (String s : list) {
if("Java".equals(s)){
list.remove(s);
}
}
// c、lambda表达式(会出现问题,因为其内部也使用的foreach遍历,这种无法解决的,Lambda遍历不能边遍历边删除,会出bug)
list.forEach(s -> {
if("Java".equals(s)){
list.remove(s);
}
});
// d、for循环(边遍历边删除集合没毛病,但是必须从后面开始遍历删除才不会出现漏掉应该删除的元素)
for (int i = list.size() - 1; i >= 0 ; i--) {
String ele = list.get(i);
if("Java".equals(ele)){
list.remove(ele);
}
}