List集合系列
List接口
-
List集合存储元素的特点:有序可重复。有序表示List集合中的元素是有下标的,存进去的顺序和取出来的顺序相同。可重复表示List集合中可以存放相同的元素。
-
List接口是Collection接口的子接口,子接口中会有一些特有的方法,这些方法是父类Collection无法使用的。
-
List集合特有的方法:
方法 解释 void add(int index , E element) 向指定下标上插入元素element E get(int index) 获取下标位置上的元素 int indexOf(Object o) 获取对象o在当前集合中第一次出现的下标 int lastIndexOf(Object o) 获取对象o在当前集合中最后一次出现的下标 E remove(int index) 删除下标位置上的元素 E set(int index , E element) 将指定下标index上的元素,替换成element List<E> subList(int fromIndex , int toIndex) 从当前集合中截取一个子List集合 -
以ArrayList集合为例,编写程序测试List集合接口中的方法:
public class Test { public static void main(String[] args) { // 创建ArrayList集合 List<String> list = new ArrayList<>(); // 添加元素 list.add("zhangsan"); list.add("lishi"); list.add("wangwu"); list.add("lishi"); // 向下标第一个位置上插入元素 list.add(0,"zhaoliu"); // 遍历集合 System.out.print("遍历集合:"); for(String x : list){ System.out.print(x + " "); } // 获取下标第一个位置上的元素 System.out.println("\n下标第一个位置上的元素:" +list.get(0)); // 获取 "lishi" 在当前集合中第一次出现的下标 System.out.println("lishi第一次出现的下标:" +list.indexOf("lishi")); // 获取 "lishi" 在当前集合中最后一次出现的下标 System.out.println("lishi第一次出现的下标:" +list.lastIndexOf("lishi")); // 删除下标最后一个位置上的元素 list.remove(list.size()-1); // 将下标最后一个位置上的元素替换成aaa list.set(list.size()-1,"aaa"); // 从当前集合中截取一个子List集合 List<String> subList = list.subList(1, list.size() - 1); // 遍历集合 System.out.print("遍历集合:"); for(String x : list){ System.out.print(x + " "); } // 遍历子集合 System.out.print("\n遍历子集合:"); for(String x : subList){ System.out.print(x + " "); } } } 运行结果: 遍历集合:zhaoliu zhangsan lishi wangwu lishi 下标第一个位置上的元素:zhaoliu lishi第一次出现的下标:2 lishi第一次出现的下标:4 遍历集合:zhaoliu zhangsan lishi aaa 遍历子集合:zhangsan lishi
-
从以上方法可以看到List集合中的元素是可以通过下标获取的,除了通过迭代器进行遍历,还可以通过下标进行遍历,通过下标进行遍历这是List集合特有的,Set集合不能使用。例如:
public class Test { public static void main(String[] args) { // 创建ArrayList集合 List<String> list = new ArrayList<>(); // 添加元素 list.add("张三"); list.add("李四"); list.add("王五"); list.add("赵六"); // 遍历 for (int i=0;i<list.size();i++){ //获取下标位置上的元素 String s = list.get(i); System.out.println(s); } } } 运行结果: 张三 李四 王五 赵六
List集合系列——ArrayList
-
ArrayList集合底层采用的是数组这种数据结构。
-
-
通过源码可以看出ArrayList集合底层是Object[]数组。数组的特点:检索效率较高,随机增删效率较低(不包括末尾),向末尾添加元素或删除元素不涉及元素位移效率较高。
-
关于ArrayList初始容量和扩容?
-
初始容量:ArrayList集合在刚new出来的时候,底层数组长度为0,只有在添加第一个元素的时候,才会扩容到10。
-
扩容:当添加第一个元素之后,初始容量10满了进行扩容,扩容规则:新容量是原容量的1.5倍。
-
-
ArrayList集合在使用的时候需要注意优化,可以在使用之前预估计集合中存储元素的数量,给定一个初始化容量,这样可以减少底层数组的扩容,也可以提高程序的执行效率。
List集合系列——LinkedList
-
LinkedList集合底层是双向链表这种数据结构。链表数据结构包括:单向链表,双向链表,循环链表。
-
链表数据结构中最基本的单元是结点,这里使用单链表为例:对于单链表来说,每一个结点由两部分组成,一部分是存储数据的data,另一部分是存储下一个结点的内存地址next,每个结点在空间存储上内存地址不是连续的,和数组完全不同。例如:
-
-
以上就是单链表数据结构,每一个结点包含两部分,data和next,尾结点的next为null,结点Node类的代码大概如下:
public class Node{ // 存放结点中的数据 Object data; // 存放下一个结点的内存地址 Node next; }
-
由于每个结点在空间存储上内存地址是不连续的,无法通过数学表达式计算查找元素的内存地址,只能从头结点开始查找,通过第一个结点找到第二个结点,以此内推。所以链表查找效率较低,但由于内存地址不连续,添加或者删除不涉及元素位移,所以链表在随机增删元素效率较高。
-
双向链表数据结构图:
-
-
以上是双向链表数据结构,每个结点对象有三个属性,data,prev(上一个结点内存地址),next(下一个结点内存地址),头结点可以持有尾结点的内存地址,尾结点可以持有头结点的内存地址,因此双向链表可以从头结点开始查找,也可以从尾结点开始查找,更加灵活。
List集合系列——Vector
-
Vector集合底层也是一个数组数据结构,和ArrayList集合一样Object[]数组,只不过Vector是线程安全的,其类中的方法都是线程安全的,被synchronized修饰。由于Vector集合是线程安全的,这种线程安全处理方式导致集合的处理速度变慢,所以现在很少用了。
-
关于Vector集合的初始化容量和扩容?
-
初始化容量:初始化容量为10。
-
扩容:扩容之后的容量是之前原容量的2倍。
-