List
集合概述
前面我们说过,Collection
接口有两个重要的后代,一个是Set接口,一个是List
接口。最大的区别在于:List
接口以及他的实现集合(Vector,LinkedList,ArrayList
)是有下标索引的,而且可以存储重复元素。
那么自然,List接口独有的一些抽象方法大多都是与下标有关的。
还有就是,我们知道java中队列的实现是用LinkedList<E>
,所以LinkedList<E>
是先进先出,后进后出,入队顺序和出队顺序是一致的,其实不仅仅是LinkedList<E>
,List接口的实现类都是有序的,即存储的是1 2 3,取出的也是 1 2 3。
List
集合特有方法
说了这么多,List
的最大特点就是有下标,所以List
接口的特有方法也都是和下标相关。List
特有的四大方法,分别是带下标的get,add,remove,set
方法。
代码如下
import java.util.List;
import java.util.LinkedList;
public class Main{
public static void main(String[] args){
//使用多态,但List索引访问的都是被LinkedList重写过得List的抽象方法
List<String> myList=new LinkedList<String>();
myList.add("周芷若");//不带下标的add是Collection接口就有的,List继承了下来;
myList.add("周芷若");//实现List接口的集合都可以重复
myList.add("赵敏");
myList.add("灭绝师太");
myList.add("丁敏君");
myList.add("小昭");
myList.add("杨不悔");
myList.add("苍井空");
System.out.println(myList);//显示的不是地址,说明重写了从Object继承来的toString()
System.out.println("============================");
//下面开始List特有方法
myList.remove(7);//苍井空煞风景,我们删掉他
System.out.println(myList);
System.out.println("============================");
//我们使用带下标的add,把灭绝师太的情人插入下标为4的位置
myList.add(4,"光明右使范遥");
System.out.println(myList);
System.out.println("============================");
System.out.println(myList.get(3));//返回下标元素
System.out.println("============================");
//我们使用set函数重置某下标结点元素的值
myList.set(3,"灭绝老尼姑");
System.out.println(myList);
}
}
运行结果如下:
实现List接口的集合的遍历
这个前面讲迭代器的时候讲过了,没下标的,使用迭代器遍历,也可以使用增强for
(foreach
的本质还是迭代器),不过还是迭代器更灵活。
现在有下标了,除了前面两种,还有就是普通的for
也可以遍历啦。
ArrayList集合
有同学可能会问,ArrayList,Linked,Vector
这三个集合不都是差不多嘛?为什么要学三个呢?学一个不好吗?
这三个集合的使用和操作确实是差不多,但他们的底层却天差地别,也就导致每个集合都有它擅长的方面和不擅长的方面。
先从ArrayList
开始说,读过ArrayList
底层代码的同学知道,ArrayList
的底层就是数组,一看是数组,我们就知道了ArrayList
的特性:存储读取快(读取存储是真的快,因为采用了多线程,所以存储和读取要比普通数组还快!虽然都是O(n)
.),增删慢。
也就是说,我们如果有大量的读取存储的时候,采用ArrayList
,如果增删多的话,用ArrayList
简直就是灾难!同学们可以自己想一想,他的底层数组是怎么实现增删的?C++扎实的同学都知道,封装过的数组所谓的增删,实际上就是不断开辟新的数组,选择性赋值,然后改变指针指向的过程!
(什么,你以为还是每个元素后移前移吗,那是C,那种增删就更慢了)
可想而知,用ArrayList做增删的效率是多么的底下!
不过读取和存储就很快了。记住ArrayList
底层是数组,你就知道什么时候用他,什么时候不用了。
LinkedList集合
ArrayList
的底层是数组,猜一猜,LinkedList
的底层是什么?
哈哈,其实他们的名字已近告诉你了,Array
是数组,所以ArrayList
的底层是数组,即“用数组实现List接口”,Link
是链,所以LinkedList
当然就是用链表实现List
接口啦。既然LinkedList
的底层是链表,那么他的使用情况就呼之欲出了,增删快,读取存储慢,刚好和数组相反。
值得一提的是,LinkedList
除了在大量增删数据的时候使用以外,还担当着java中一个重要的功能:队列。是的,LinkedList
天然就可以当做队列使用。而且契合的最好。因为传统的队列只能队尾进,队头删除,LinkedList
就超级厉害。简单来说,就是LinkedList使用是既可以把他当成普通队列,也可以当成双端队列。所以我们在Java实现数据结构的时候,BFS算法需要用到队列,就是使用LinkedList
来承当队列的。(add就是队尾入队,removeFirst就是队首出队)而且,LinkedList还可以作为数据结构的堆栈!
我们来演示一下LinkedList在数据结构中的用法!
LinkedList作为堆栈:
import java.util.LinkedList;
public class Main{
public static void main(String[] args){
LinkedList<String> myLink=new LinkedList<String>();
myLink.push("郭靖");
myLink.push("黄蓉");
myLink.push("小龙女");
myLink.push("尹志平");
System.out.println(myLink.pop());
System.out.println(myLink);
}
}
运行结果
最典型的堆栈
LinkedList作为普通队列
import java.util.LinkedList;
public class Main{
public static void main(String[] args){
LinkedList<String> myLink=new LinkedList<String>();
myLink.add("郭靖");
myLink.add("黄蓉");
myLink.add("小龙女");
myLink.add("尹志平");
System.out.println(myLink.removeFirst());
System.out.println(myLink);
}
}
运行结果如下
最典型的队列
所以LinkedList
集合既可以作为数据结构中的队列,又可以作为数据结构中的堆栈,却是方便。注意在使用LinkedList
充当堆栈或者队列的时候,不要使用多态,因为充当堆栈队列的方法大多都是LinkedLis
t的特有方法,多态看不到子类特有的方法。
Vector集合
这是最早为了实现变长数组做出来的集合(和C++里面STL的一样),现在已经废了(单线程,所以被ArrayList取代了)。