什么是List
List接口是在Java中继承自Collection接口,是一个有序的集合,用来存储一组数据,可以暂且的将他理解成一个数组来看待,但是他比起数组有着更丰富快捷的使用方法。
List的特点
有序、允许值的重复
实现类
ArrayList类
数据结构
ArrayList基于Object[ ]数组实现Object[ ]ElementData
扩容方式
初始化
1.public ArrayList( )——无参构造方法,将内部数组初始化为一个长度位0的数组。
eg.
public static void main(String[] args) {
ArrayList<String> str=new ArrayList<>();
}
2.public ArrayList(int initialCapacity)——将内部数组初始化为一个长度为()中数字长度的数组
有利于后续输入数组时,扩容对资源的占用。
eg.
public static void main(String[] args) {
ArrayList<String> str=new ArrayList<>(10);
}
扩容
1.如果使用了无参构造方法来创建ArrayList则默认长度为0,担当添加任何一个元素后,数组的长度就会扩容至10.
2.当数组元素被添加满担当前容量,则数组的长度会自动扩容至原来容量的1.5倍。
3.数组的最大容量在Integer.MAX_VALUE-8至Integer.MAX_VALUE之间,如果超出,则抛出OutOfMemoryError错误
Ps
这里就可以体现出为何要使用ArrayList的有参构造方法来初始化内部数组的长度,因为每当数组内元素数量多出该数组的长度后,JVM会自动将此数组扩容至其原来的1.5倍,如果数组的元素过多,扩容多次的话,每次的扩容就会对资源进行占用造成资源浪费,这时就不如程序员在开发过程中就对数组内元素数量进行一个预估,给内部数组初始化一个大致的长度,来减少数组扩容对资源的占用。
适用场景
ArrayList 适合数据连续性遍历,读多写少的场景
常用方法
添加新元素
1.boolean add(E e)——添加新元素至集合尾部
2.void add(int index, E element)——添加新元素至集合指定下标位置
3.boolean addAll(Collection c)——添加集合内所有元素至当前集合
eg.
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("貂蝉");
list.add("貂蝉");
list.add(1,"小乔");
list.addAll(Arrays.asList("南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
System.out.println(list);
}
//输出内容
//[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
获取元素
1.E get(int index)——获取指定位置下标的元素
2.List<E> subList(int fromIndex, int toIndex)——按照指定下标区间截取子集合
eg.
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("貂蝉");
list.add("貂蝉");
list.add(1,"小乔");
list.addAll(Arrays.asList("南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
String s= list.get(3);
List<String> str1=new ArrayList<>(list.subList(4,8));
System.out.println(s);
System.out.println(str1);
}
//输出内容
//南拳妈妈
//[腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺]
判断元素
1.boolean contains(Object o)——判断集合中是否存在元素
2.boolean equals(Object o)——判断两个集合中的元素是否相同
3.int indexOf(Object o)——查找指定元素的下标位置,如果不存在,则返回-1
eg.
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("貂蝉");
list.add("貂蝉");
list.add(1,"小乔");
list.addAll(Arrays.asList("南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
ArrayList<String> list2=new ArrayList<>();
list2.addAll(Arrays.asList("貂蝉","小乔","貂蝉","南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
ArrayList<String> list3=new ArrayList<>();
//判断数组中是否含有元素:
System.out.println(list.contains("伍佰"));
System.out.println(list.contains("五百"));
System.out.println("=====================");
//判断两个集合的元素是否相等
System.out.println(list);
System.out.println(list2);
System.out.println(list3);
System.out.println(list.equals(list2));
System.out.println(list.equals(list3));
System.out.println("======================");
//查找指定元素下标,有则返回下标,无则返回-1
System.out.println(list.indexOf("伍佰"));
System.out.println(list.indexOf("五百"));
}
/*输出内容
true
false
=====================
[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
[]
true
false
======================
10
-1
*/
删除元素
1.void clear()——清空集合
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.addAll(Arrays.asList("貂蝉", "小乔", "貂蝉", "南拳妈妈", "腾格尔", "奥斯特洛夫斯基", "张杰", "易烊千玺", "信", "梦龙乐队", "伍佰"));
list.clear();
System.out.println(list);
}
//输出
//[]
2.boolean remove(Object o)——删除指定内容的元素
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.addAll(Arrays.asList("貂蝉","小乔","貂蝉","南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
System.out.println("原数组"+list);
list.remove("易烊千玺");
System.out.println("删除指定元素\"易烊千玺\"后的数组"+list);
}
/*输出内容
原数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
删除指定元素下标"7"后的数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 信, 梦龙乐队, 伍佰]
*/
3.E remove(int index)——删除指定位置的元素
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.addAll(Arrays.asList("貂蝉","小乔","貂蝉","南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
System.out.println("原数组"+list);
list.remove(7);
System.out.println("删除指定元素下标\"7\"后的数组"+list);
}
/*输出内容
原数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
删除指定元素下标"7"后的数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 信, 梦龙乐队, 伍佰]
*/
4.boolean removeAll(Collection c)——删除当前集合与指定集合的相同元素
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.addAll(Arrays.asList("貂蝉","小乔","貂蝉","南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
ArrayList<String> list2=new ArrayList<>();
list2.addAll(Arrays.asList("GGBond","SpiderMan","IronMan","Thor","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
System.out.println("原数组list"+list);
System.out.println("原数组list2"+list2);
list.removeAll(list2);
System.out.println("删除当前集合与指定集合的相同元素\"list2\"后的数组"+list);
}
/*输出内容
原数组list[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
原数组list2[GGBond, SpiderMan, IronMan, Thor, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
删除当前集合与指定集合的相同元素"list2"后的数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔]
*/
5.boolean retainAll(Collection c)——保留当前集合与指定集合的相同元素,删除其余元素
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.addAll(Arrays.asList("貂蝉","小乔","貂蝉","南拳妈妈","腾格尔","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
ArrayList<String> list2=new ArrayList<>();
list2.addAll(Arrays.asList("GGBond","SpiderMan","IronMan","Thor","奥斯特洛夫斯基","张杰","易烊千玺","信","梦龙乐队","伍佰"));
System.out.println("原数组list"+list);
System.out.println("原数组list2"+list2);
list.retainAll(list2);
System.out.println("保留当前集合与\"list2\"集合的相同元素,删除其余元素后的数组"+list);
}
/*
输出内容
原数组list[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
原数组list2[GGBond, SpiderMan, IronMan, Thor, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
保留当前集合与"list2"集合的相同元素,删除其余元素后的数组[奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
*/
修改元素
E set(int index, E element)——将指定下标位置的元素,修改为指定新元素
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.addAll(Arrays.asList("貂蝉", "小乔", "貂蝉", "南拳妈妈", "腾格尔", "奥斯特洛夫斯基", "张杰", "易烊千玺", "信", "梦龙乐队", "伍佰"));
System.out.println("原数组"+list);
list.set(1,"大乔");
System.out.println("修改后的数组"+list);
}
/*
输出内容
原数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
修改后的数组[貂蝉, 大乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
*/
排序
void sort(Comparator c)——按照Comparator接口实现类的比较规则,对集合内的元素进行排序
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.addAll(Arrays.asList("貂蝉", "小乔", "貂蝉", "南拳妈妈", "腾格尔", "奥斯特洛夫斯基", "张杰", "易烊千玺", "信", "梦龙乐队", "伍佰"));
list.sort(null);//使用默认排序方法
System.out.println("修改后的数组"+list);
}
/*
输出内容
修改后的数组[伍佰, 信, 南拳妈妈, 奥斯特洛夫斯基, 小乔, 张杰, 易烊千玺, 梦龙乐队, 腾格尔, 貂蝉, 貂蝉]
*/
若想按照自己自定义的方法排序则可重写Comparator方法
转换
T[ ] toArray(T[ ] a)——将当前集合转换为数组
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.addAll(Arrays.asList("貂蝉", "小乔", "貂蝉", "南拳妈妈", "腾格尔", "奥斯特洛夫斯基", "张杰", "易烊千玺", "信", "梦龙乐队", "伍佰"));
list.toArray();
System.out.println(list);
}
/*
输出内容
修改后的数组[貂蝉, 小乔, 貂蝉, 南拳妈妈, 腾格尔, 奥斯特洛夫斯基, 张杰, 易烊千玺, 信, 梦龙乐队, 伍佰]
*/
迭代器
1.Iterator<E> iterator()——该迭代器仅提供向后遍历
2.ListIterator<E> listIterator(int index)——该迭代器提供向前或向后遍历,并提供添加元素的操作
public static void main(String[] args) {
ArrayList<String> list=new LinkedList<>();
list.add("晁盖");
list.addFirst("宋江");
list.add(0,"武松");
list.addLast("悟空");
System.out.println(list);
System.out.println("==========================");
String item= list.get(1);
String first= list.getFirst();
String last= list.getLast();
System.out.println(item);
System.out.println(first);
System.out.println(last);
System.out.println("==========================");
System.out.println("for循环正序遍历");
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
System.out.println("正序遍历迭代器");
Iterator<String> it= list.iterator();
while (it.hasNext()){
String name=it.next();
System.out.println(name);
}
System.out.println("逆序遍历迭代器");
ListIterator<String> it1= list.listIterator(list.size());
while (it1.hasPrevious()){
String name=it1.previous();
System.out.println(name);
}
}
/*
[武松, 宋江, 晁盖, 悟空]
==========================
宋江
武松
悟空
==========================
for循环正序遍历
武松
宋江
晁盖
悟空
正序遍历迭代器
武松
宋江
晁盖
悟空
逆序遍历迭代器
悟空
晁盖
宋江
武松
进程已结束,退出代码0
*/
LinkedList类
数据结构
LinkedList是基于双向链表实现,链表中的每个节点都是一个Node类型的对象,Node对象由item、prev、next三部分组成
扩容方式
由于采用链表结构,每次添加元素,都会创建新的Node节点并分配空间,所以不存在扩容
适用场景
适合数据频繁添加删除操作,写多读少的场景
常用方法
添加元素
1.boolean add(E e)——添加新元素至链表尾部
2.void addFirst(E e)——添加新元素至链表头部
3.void addLast(E e)——添加新元素至链表尾部
public static void main(String[] args) {
LinkedList linked=new LinkedList<>();
linked.add("张飞");
linked.add("张飞");
linked.addFirst("李逵");
linked.add("张飞");
linked.add("张飞");
linked.addLast("黄盖");
System.out.println(linked);
}
/*
输出内容
[李逵, 张飞, 张飞, 张飞, 张飞, 黄盖]
*/
获取元素
1.E get(int index)——遍历链表,查找指定位置的元素
2.E getFirst()——获取链表中的头元素
3.E getLast()——获取链表中的尾元素
public static void main(String[] args) {
LinkedList linked=new LinkedList<>();
linked.add("张飞");
linked.add("张飞");
linked.addFirst("李逵");
linked.add("张飞");
linked.add("张飞");
linked.addLast("黄盖");
System.out.println(linked.get(5));
System.out.println(linked.getFirst());
System.out.println(linked.getLast());
}
/*
输出内容
黄盖
李逵
黄盖
*/
判断元素
int indexOf(Object o)——查找链表中的指定元素的下标位置,如果不存在,则返回-1
public static void main(String[] args) {
LinkedList linked=new LinkedList<>();
linked.add("张飞");
linked.add("张飞");
linked.addFirst("李逵");
linked.add("张飞");
linked.add("张飞");
linked.addLast("黄盖");
System.out.println(linked.indexOf("李逵"));
System.out.println("李白");
}
/*
输出内容
0
李白
*/
删除元素
1.E remove()——删除链表中的头元素
2.boolean remove(Object o)——删除指定内容的元素
3.E remove(int index)——删除指定位置的元素
4.E removeFirst()——删除链表中的头元素
5.E removeLast()——删除链表中的尾元素
public static void main(String[] args) {
LinkedList linked=new LinkedList<>();
linked.add("0");
linked.add("1");
linked.add("2");
linked.add("3");
linked.add("4");
linked.add("5");
linked.add("6");
linked.add("7");
linked.add("8");
linked.add("9");
linked.remove();
System.out.println("删除链表中的头元素"+linked);
linked.remove("4");
System.out.println("删除指定内容的元素\"4\""+linked);
linked.remove(5);
System.out.println("删除指定下标内容的元素\"5\""+linked);
linked.removeFirst();
System.out.println("删除链表中的头元素\"5\""+linked);
linked.removeLast();
System.out.println("删除链表中的尾元素\"5\""+linked);
}
/*
输出内容
删除链表中的头元素[1, 2, 3, 4, 5, 6, 7, 8, 9]
删除指定内容的元素"4"[1, 2, 3, 5, 6, 7, 8, 9]
删除指定下标内容的元素"5"[1, 2, 3, 5, 6, 8, 9]
删除链表中的头元素"5"[2, 3, 5, 6, 8, 9]
删除链表中的尾元素"5"[2, 3, 5, 6, 8]
*/
default void sort(Comparator c)
按照Comparator比较器,将链表中的所有元素进行排序
public static void main(String[] args) {
LinkedList linked=new LinkedList<>();
linked.add("0");
linked.add("1");
linked.add("2");
linked.add("3");
linked.add("4");
linked.add("5");
linked.add("6");
linked.add("7");
linked.add("8");
linked.add("9");
linked.sort(null);//默认比较方法
System.out.println(linked);
}
/*
输出
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
T[ ] toArray(T[ ] a)
将链表转换成数组
public static void main(String[] args) {
LinkedList linked=new LinkedList<>();
linked.add("0");
linked.add("1");
linked.add("2");
linked.add("3");
linked.add("4");
linked.add("5");
linked.add("6");
linked.add("7");
linked.add("8");
linked.add("9");
linked.toString();
System.out.println(linked);
}
/*
输出
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
*/
Vector类
略
Stack类
略
常见问题
ArrayList和LinkedList的区别
实现方式
ArrayList底层是通过数组实现的,而LinkedList底层是通过链表实现的,所以ArrayList在进行增删改查的时候,会使得其他元素移动来保持数组的连续性。而LinkedList底层由于是通过链表实现,它的存储方式是通过节点链接下一个节点来存储元素,所以LinkedList进行增删改查的时候只需要修改节点的引用即可。
访问效率
ArrayList可直接通过下标来访问元素,更加的快捷
LinkedList是通过遍历来访问元素,访问效率取决于元素存储的位置
插入和删除的效率
ArrayList由于底层使用数组实现,所以在增删改元素时需要同时对其他受影响的元素也进行改变,所以复杂度更高
LinkedList由于底层使用链表实现,所以在增删改元素时只需要改变节点的引用即可,无需对其他元素负责,复杂度更低
ArrayList和Vector的区别
线程安性
ArrayList 是非线程安全的,多个线程同时操作一个 ArrayList 实例可能会导致数据不一致的问题。
Vector 是线程安全的,它的方法都是通过 synchronized 关键字实现的,保证了多个线程对同一个 Vector 实例的安全访问。因为要进行同步,所以在性能上相对于 ArrayList 会有一些影响。
动态增长
ArrayList 和 Vector 都支持动态增长,即在不断添加元素时,集合的容量会根据需要自动扩展。它们都提供了相似的方法来控制集合的初始容量和扩容倍数。
不同之处在于,ArrayList 的扩容策略是当前容量不够时增加 50% 的容量,而 Vector 是增加当前容量的一倍。
ArrayList的扩容方式
请看此篇文章 实现类=>ArrayList类=>扩容方式 段
LinkedList的适用场景
更具以上内容,LinkedList的使用场景可以是在有频繁的插入和删除场景中