前言
List本身是Collection接口的子接口,具備了Collection的所有方法。
ListIterator是List集合特有的迭代器。
ListIterator it = list.listIterator;//取代Iterator it = list.iterator;
List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重複。
- ArrayList:底層的數據結構是數組,線程不同步,ArrayList替代了Vector,查詢元素的速度非常快。
- LinkedList:底層的數據結構是鏈表,線程不同步,增刪元素的速度非常快。
- Vector:底層的數據結構就是數組,線程同步的,Vector無論查詢和增刪都巨慢。
一、List接口
1.1 List接口概述
List類型集合特點:集合中的元素有序且可重複,有下標 。
注:有序指的是元素放到集合中的順序和循環遍歷出來的順序一致。
List接口常見的實現類有:ArrayList、LinkedList、Vector等
對於數據的隨機訪問,ArrayList效率優於LinkedList,因爲LinkedList要移動指針。
對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據。
Vector是線程安全的集合,但是速度慢。
1.2 迭代器
在講集合之前我們先來說一下迭代器,因爲之後我們遍歷數據的時候要用到迭代器。
1)迭代器原理
迭代器是對集合進行遍歷,而每一個集合內部的存儲結構都是不同的,所以每一個集合存和取都是不一樣,
那麼就需要在每一個類中定義hasNext()和next()方法,這樣做是可以的,但是會讓整個集合體系過於臃腫,
迭代器是將這樣的方法向上抽取出接口,然後在每個類的內部,定義自己迭代方式,這樣做的好處有二,第一規定
了整個集合體系的遍歷方式都是hasNext()和next()方法,第二,代碼有底層內部實現,使用者不用管怎麼實現
的,會用即可 。
2)Iterator中的方法
boolean hasNext()
如果仍有元素可以迭代,則返回 true。
E next()
返回迭代的下一個元素。
void remove()
從迭代器指向的 collection 中移除迭代器返回的最後一個元素
3)ListIterator接口
ListIterator是Iterator的子接口。那爲什麼要有這個特定的子接口呢?
在迭代時,不可以通過集合對象的方法操作集合中的元素。因爲會發生ConcurrentModificationException
異常。所以,在迭代器時,只能用迭代器的放過操作元素,可是Iterator方法是有限的,只能對元素進行判斷,
取出,刪除的操作.如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。該接口只能
通過List集合的listIterator方法獲取。
ListIterator方法:
boolean hasNext()是否有下一個
boolean hasPrevious()是否有前一個
Object next()返回下一個元素
Object previous();返回上一個元素
1.3 List中特有的方法
增
add(index,element);
addAll(index,Collection);
刪
remove(index);
改
set(index,element);
查
get(index):
subList(from,to);
listIterator();
int indexOf(obj):獲取指定元素的位置。
ListIterator listIterator();
舉例:
//通過size()和get()方法結合使用遍歷
List<Student> list = new ArrayList<>();
list.add(new Student("張三",12));
list.add(new Student("李四",23));
list.add(new Student("王五",54));
list.add(new Student("小二",34));
for (int i = 0; i <list.size() ; i++) {
Student s = (Student)list.get(i);
System.out.println(s.getName()+":"+s.getAge());
}
1.4 集合中併發修改異常產生的原因及解決方案
需求:我有一個集合,請問,我想判斷裏面有沒有”hello”這個元素,如果有,我就添加一個”world”
元素,請寫代碼實現。
List<String> list = new ArrayList<>();
list.add("meinv");
list.add("gt");
list.add("ecg");
list.add("hello");
list.add("bvc");
list.add("aew");
Iterator<String> it = list.iterator();
while (it.hasNext()){
String str = (String)it.next();
if(str.equals("hello")){
list.add("world"); //這裏會拋出ConcurrentModificationException併發修改異常
}
}
解決方案:
迭代器迭代元素,迭代器修改元素(ListIterator的特有功能add)
集合遍歷元素,集合修改元素
ListIterator lit = list.listIterator(); //如果想在遍歷的過程中添加元素,可以用ListIterator中的add方法
while(lit.hasNext()) {
String str = (String)lit.next();
if(str.equals("hello")) {
lit.add("world");
//list.add("world");
}
}
二、List實現類
2.1 ArrayList
1)ArrayList去除集合中字符串的重複值(字符串的內容相同)
我們可以創建一個新的集合去存儲沒有重複值的集合
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("b");
list.add("c");
list.add("c");
list.add("c");
list.add("c");
System.out.println(list);
ArrayList newList = getSingle(list);
System.out.println(newList);
}
/*
* 去除重複
* 1,返回ArrayList
* 2,參數列表ArrayList
*/
public static ArrayList getSingle(ArrayList list) {
ArrayList newList = new ArrayList(); //創建一個新集合
Iterator it = list.iterator(); //獲取迭代器
while(it.hasNext()) { //判斷老集合中是否有元素
String temp = (String)it.next(); //將每一個元素臨時記錄住
if(!newList.contains(temp)) { //如果新集合中不包含該元素
newList.add(temp); //將該元素添加到新集合中
}
}
return newList; //將新集合返回
}
2)去除ArrayList中重複自定義對象元素
分析:
我們通過查看上面的例子中,contains()方法底層也是通過equals來做判斷的,所以這裏我們需要
判斷自定義對象的話,我們需要在Student類中重寫equals方法。
這裏我們使用contains()方法判斷是否包含,底層依賴的是equals()方法
remove()方法判斷是否刪除,底層依賴的也是equals()方法
remove源碼:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
Student類:
package com.zyh.domain;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) {
Student s = (Student)obj;
return this.name.equals(s.name)&&this.age==this.age;
}
}
ArrayListDemo:
package com.zyh.Collection.List;
import com.zyh.domain.Student;
import java.util.ArrayList;
import java.util.ListIterator;
//去除ArrayList中重複的Student對象元素
public class ArrayListDemo_0010 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("哥哥",34));
list.add(new Student("姐姐",23));
list.add(new Student("弟弟",15));
list.add(new Student("花花",13));
list.add(new Student("姐姐",23));
list.add(new Student("花花",13));
list.add(new Student("弟弟",15));
list.add(new Student("花花",13));
list.add(new Student("哥哥",34));
ArrayList<Student> newList =getSignle(list);
ListIterator<Student> slit = newList.listIterator();
while (slit.hasNext()){
Student s = slit.next();
System.out.println(s.getName()+":"+s.getAge());
}
}
public static ArrayList<Student> getSignle(ArrayList<Student> list){
ListIterator<Student> slit = list.listIterator();
ArrayList<Student> newList = new ArrayList<>();
while (slit.hasNext()){
Student s = slit.next();
while (!newList.contains(s)){
newList.add(s);
}
}
return newList;
}
}
2.2 LinkedList
1)LinkedList特有的方法
public void addFirst(E e)及addLast(E e)
public E getFirst()及getLast()
public E removeFirst()及public E removeLast()
public E get(int index);
2)用LinkedList模擬棧數據結構的集合並測試
棧:先進後出 隊列:先進先出
需求:請用LinkedList模擬棧數據結構的集合,並測試
Stack詳細實現類:
public class Stack<T>
{
private LinkedList<T> stack;
//無參構造函數
public Stack()
{
stack=new LinkedList<T>();
}
//構造一個包含指定collection中所有元素的棧
public Stack(Collection<? extends T> c)
{
stack=new LinkedList<T>(c);
}
//入棧
public void push(T t)
{
stack.addFirst(t);
}
//出棧
public T pull()
{
return stack.remove();
}
//棧是否爲空
boolean isEmpty()
{
return stack.isEmpty();
}
//打印棧元素
public void display()
{
for(Object o:stack)
System.out.println(o);
}
}
模擬類:
public class Stack {
private LinkedList list = new LinkedList(); //創建LinkedList對象
public void in(Object obj) {
list.addLast(obj); //封裝addLast()方法
}
public Object out() {
return list.removeLast(); //封裝removeLast()方法
}
public boolean isEmpty() {
return list.isEmpty(); //封裝isEmpty()方法
}
}
2.3 Vector
1)特有方法
public void addElement(E obj)
public E elementAt(int index)
public Enumeration elements()
2)使用枚舉遍歷
Vector v = new Vector(); //創建集合對象,List的子類
v.addElement("a");
v.addElement("b");
v.addElement("c");
v.addElement("d");
//Vector迭代
Enumeration en = v.elements(); //獲取枚舉
while(en.hasMoreElements()) { //判斷集合中是否有元素
System.out.println(en.nextElement());//獲取集合中的元素
}
三、List接口三個子類的特點與區別
2.1 List接口三個子類的特點
- ArrayList
底層數據結構是數組,查詢快,增刪慢。
線程不安全,效率高。 - Vector
底層數據結構是數組,查詢快,增刪慢。
線程安全,效率低。
Vector相對ArrayList查詢慢(線程安全的)
Vector相對LinkedList增刪慢(數組結構) - LinkedList
底層數據結構是鏈表,查詢慢,增刪快。
線程不安全,效率高。
2.2 List接口三個子類的區別
- Vector和ArrayList比較
區別:Vector是線程安全的,效率低。ArrayList是線程不安全的,效率高。
共同點:都是數組實現的 - ArrayList和LinkedList的區別
區別:ArrayList底層是數組實現,查詢和修改快。
LinkedList底層是鏈表結構的,增和刪比較快,查詢和修改比較慢。
共同點:都是線程不安全的