一 List 接口
1.1 概述
- 有序的集合(存储和取出元素顺序相同)
- 允许存储重复元素。
- 有索引,可以使用普通的for循环遍历
1.2 常用方法
- public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
- E remove(int index):删除指定索引处的元素,返回被删除的元素,也可以删除指定的元素
- E set(int index,E element):修改指定索引处的元素,返回被修改的元素
- E get(int index):返回指定索引处的元素
public class ListDemo {
public static void main(String[] args) {
//创建一个List集合对象,多态
List<String> list = new ArrayList<>();
//使用add方法往集合中添加元素
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
System.out.println(list);//[a,b,c,d,a]
//public void add(int index, E element)`: 将指定的元素,添加到该集合中的指定位置上。
//在c和d之间添加z
list.add(3,"z");
System.out.println(list); // [a, b, c, z, d, a]
// E remove(int index):删除指定索引处的元素,返回被删除的元素,也可以删除指定的元素
list.remove(2);
System.out.println(list); //[a, b, z, d, a]
list.remove("d");
System.out.println(list); // [a, b, z, a]
//E set(int index,E element):修改指定索引处的元素,返回被修改的元素
list.set(0,"s");
System.out.println(list); //[s, b, z, d, a]
// E get(int index):返回指定索引处的元素
System.out.println(list.get(list.size()-1)); //a
}
}
1.3 实现类
- ArrayList
- LinkedList
1.3.1 ArrayList
- ArrayList底层数据是数组,查询快,增删慢
- 空参构造会创建一个长度为0的数组,当调用add方法会创建一个长度为10的数组,在底层叫做elementData,还会存在一个变量 size 它表达下一次要操作的索引,也表达数组元素的个数
- 如果数组填满,数组会自动扩容,创建一个长度1.5倍的数组(jdk1.8),在jdk1.7的时候会直接创建一个容量为10的数组
- 查询根据数组的地址值跟索引来获取,底层会判断你这个索引会不会大于等于size如果大于等于就报错
1.3.1.1 特有方法
- int indexOf(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
- boolean addAll(Collection<? extends E> c) 按照指定 collection 集合的迭代器所返回的元素顺序,将该 collection 集合中的所有元素添加到此列表的尾部。
- boolean addAll(int index, Collection<? extends E> c) 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。
- Object[] toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。
- T[] toArray(T[] a) 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。
public class ArrayListDemo{
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
System.out.println(list); // [a, b, c, d]
// 1.int indexOf(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
int index1 = list.indexOf("a");
int index2 = list.indexOf("z");
System.out.println("a的索引: " + index1); // a的索引num1: 0
System.out.println("z的索引: " + index2); // z的索引num2: -1
System.out.println("-------------------------------------------------");
// 2.boolean addAll(Collection<? extends E> c) 按照指定 collection 集合的迭代器所返回的元素顺序,将该 collection 集合中的所有元素添加到此列表的尾部。
ArrayList<String> list2=new ArrayList<>();
//将list集合作为参数传递给list2的addAll方法
list2.addAll(list);
System.out.println(list2); // [a, b, c, d]
list2.addAll(list);
System.out.println(list2); // // [a, b, c, d]
// 3.boolean addAll(int index, Collection<? extends E> c) 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。
System.out.println("-------------------------------------------------");
list2.addAll(2,list);
System.out.println(list2); // [a, b, a, b, c, d, c, d, a, b, c, d]
// 4.Object[] toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。
Object[] objects = list2.toArray();
for (Object object : objects) {
System.out.println(object);
}
System.out.println("-------------------------------------------------");
// 5.T[] toArray(T[] a) 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。
String[] strArr=new String[list2.size()];
String[] strArr2 = list2.toArray(strArr);
for (int i = 0; i < strArr2.length; i++) {
System.out.println(strArr2[i]);
}
}
}
1.3.2 LinkedList
- LinkedList 的底层是双向链表, 在 LinkedList 内部,有 size、first、last 属性以及一个内部类 Node,所以LinkedList查询慢,增删快
- 底层代码中包含了大量的链表操作的方法
public class LinkedListDemo1 {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("1");
linkedList.add("2");
linkedList.add("3");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
for (String s : linkedList) {
System.out.println(s);
}
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
1.3.2.1 特有方法
- public void addFirst(E e)`:将指定元素插入此列表的开头。
- public void addLast(E e)`:将指定元素添加到此列表的结尾。
- public E getFirst()`:返回此列表的第一个元素。
- public E getLast()`:返回此列表的最后一个元素。
- public E removeFirst()`:移除并返回此列表的第一个元素。
- public E removeLast()`:移除并返回此列表的最后一个元素。
- public E pop()`:从此列表所表示的堆栈处弹出一个元素。
- public void push(E e)`:将元素推入此列表所表示的堆栈。
- public boolean isEmpty()`:如果列表不包含元素,则返回true。
public class LinkedListDemo2 {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("111");
linkedList.add("222");
linkedList.add("333");
linkedList.add("444");
//1.public void addFirst(E e)`:将指定元素插入此列表的开头。
linkedList.addFirst("000");
System.out.println(linkedList); // [000, 111, 222, 333, 444]
//2.public void addLast(E e)`:将指定元素添加到此列表的结尾。
linkedList.addLast("555");
System.out.println(linkedList); // [000, 111, 222, 333, 444, 555]
//3.public E getFirst()`:返回此列表的第一个元素。
System.out.println(linkedList.getFirst()); // 000
//4.public E getLast()`:返回此列表的最后一个元素。
System.out.println(linkedList.getLast()); // 555
//5.public E removeFirst()`:移除并返回此列表的第一个元素。
linkedList.removeFirst();
System.out.println(linkedList); // [111, 222, 333, 444, 555]
//6.public E removeLast()`:移除并返回此列表的最后一个元素。
linkedList.removeLast();
System.out.println(linkedList); // [111, 222, 333, 444]
//7.public E pop()`:从此列表所表示的堆栈处弹出一个元素。
System.out.println(linkedList.pop()); // 111
//8.public void push(E e)`:将元素推入此列表所表示的堆栈。
linkedList.push("push");
System.out.println(linkedList); // [push, 222, 333, 444]
//9.public boolean isEmpty()`:如果列表不包含元素,则返回true。
System.out.println(linkedList.isEmpty()); // false
}
}
1.3.3 Vector
- Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。
- 在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。
- 注:因为Vector的底层大量的使用了 synchronized关键字导致性能过低已经被抛弃使用
1.3.3.1 新增方法
- void addElement(Object obj) 将指定的组件添加到此向量的末尾,将其大小增加 1。
- void insertElementAt(Object obj,int index) 将指定对象作为此向量中的组件插入到指定的 index 处。
- void setElementAt(Object obj,int index) 将此向量指定 index 处的组件设置为指定的对象。
- void removeElement(Object obj) 从此向量中移除变量的第一个(索引最小的)匹配项。
- void removeAllElements() 从此向量中移除全部组件,并将其大小设置为零。
1.3.4 面试题
请问ArrayList/LinkedList/Vector的异同?谈谈你的理解?ArrayList底层是什么?扩容机制?Vector和ArrayList的最大区别?
- ArrayList和LinkedList的异同
- 二者都线程不安全,相对线程安全的Vector,执行效率高。
此外,ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。对于新增和删除操作add(特指插入)和remove,LinkedList比较占优势,因为ArrayList要移动数据。
- 二者都线程不安全,相对线程安全的Vector,执行效率高。
- ArrayList和Vector的区别
- Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于强同步类。因此开销就比ArrayList要大,访问要慢。正常情况下,大多数的Java程序员使用ArrayList而不是Vector,因为同步完全可以由程序员自己来控制。Vector每次扩容请求其大小的2倍空间,而ArrayList是1.5倍。Vector还有一个子类Stack。