Java集合Collection接口之List子接口

List接口介紹

List接口是有序的collection(也稱爲序列,這個有序不是指的自然順序,而是指添加進集合中的順序與元素出來的順序一致),用戶可以對列表中每個元素的插入位置進行精確地控制。用戶可以根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。

主要的實現類有如下三個: 
ArrayList :底層是維護了一個Objecy數組實現的,特點:查詢速度快,增刪慢; 
LinkedList:底層是使用了鏈表數據結構實現的,特點:查詢速度慢,增刪塊; 
Vector:底層維護了一個Object的數組實現的,實現與ArratList是一樣的,但是Vector是線程安全的,同步的,操作效率低

實現方法

除了Collection接口實現的一些方法外,List接口有一些特有的方法,可以使用索引index快速操作,

  • 1:增加 
    void add(int index, E element) 指定位置添加元素 
    boolean addAll(int index, Collection c) 指定位置添加集合
  • 2:刪除 
    E remove(int index) 刪除指定位置元素
  • 3:修改 
    E set(int index, E element) 返回的是需要替換的集合中的元素
  • 4:查找: 
    E get(int index) 注意: IndexOutOfBoundsException 
    int indexOf(Object o) // 找不到返回-1 
    lastIndexOf(Object o)
  • 5:求子集合 
    List subList(int fromIndex, int toIndex) // 不包含toIndex
  • 6.迭代器 
    listIterator(int index) 
    List接口還提供了特殊的迭代器,稱爲ListIterator,除了允許Iterator接口提供的正常操作外,該迭代器還允許元素的差入和替換,以及雙向訪問,還提供了一個方法來獲取從列表中指定位置開始的列表迭代器。 
    ListIterator迭代器特有方法: 
    hasPrevious() 判斷是否存在上一個元素 
    previous:指針先向上移動一個單位,然後取出當前指向的元素 
    next():先取出當前指向的元素,然後指針向下移動一個單位 
    set(E e) :用指定元素替換next或previous返回的最後一個元素

遍歷集合的方法

使用三種方法遍歷集合的元素:

  • 1.使用get方法遍歷
  • 2.使用迭代器正序遍歷
  • 3.使用迭代器逆序遍歷
//get方法遍歷
for(int i = 0 ; i<list.size() ; i++){
System.out.print(list.get(i)+",");
}
//使用迭代器正序遍歷
ListIterator it = list.listIterator(); //獲取到迭代器
while(it.hasNext()){
System.out.print(it.next()+",");
}
 
//使用迭代器逆序遍歷
while(it.hasPrevious()){
System.out.print(it.previous()+",");
}

注意: 
在使用迭代器迭代元素的過程中,不允許使用集合對象改變集合中的元素個數,若需要添加或刪除只能使用迭代器的方法進行操作;若使用了集合對象改變,則會報ConcurrentModificationException異常。

實現類ArrayList使用

ArrayList實現類是類似於一個可變數組,長度可動態變化,允許包含null元素。此實現類不是同步的,若有多個線程同時訪問一個ArrayList實例,而其中有一個線程從結構上修改了列表,那麼它必須保持外部同步。(結構上的修改是指任何添加或刪除一個或多個元素的操作,或者顯式調整底層數組的大小,僅僅設置元素的值不是結構上的修改) 
ArrayList實現類的定義源碼如下:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
private transient Object[] elementData; //存儲ArrayList內的元素,transient 關鍵字關閉序列化
private int size; //表示ArrayList內的元素個數
 
public ArrayList(int initialCapacity) { //構造一個具有指定初識容量的列表
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList() {
this(10);
}
public ArrayList(Collection<? extends E> c) { //構造一個具有指定collection的元素的列表
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}

ArrayList類繼承了AbstractList(此類提供了List接口的主要實現),實現了List接口;
    RandomAccess是一個標記接口,用來表明其支持快速(通常是固定時間)隨機訪問(在這裏的快速隨機訪問我的理解就是可以通過下標直接訪問數組,已達到快速訪問); 
    實現Cloneable接口,以指示 Object.clone() 方法可以合法地對該類實例進行按字段複製; 
    實現java.io.Serializable接口,這意味着ArrayList支持序列化,能通過序列化去傳輸,所謂的序列化就是將實現了Serializable接口的對象轉換成一個字節序列,並能夠在以後將這個字節序列完全恢復爲原來的對象,可以通過網絡進行,序列化機制能自動彌補不同操作系統之間的差異。(對於序列化的理解,參看https://my.oschina.net/u/1382972/blog/170148 ) 
    transient 關鍵字:若是實現了Serializable接口進行序列化功能,那麼所有序列化操作都會自動進行,對於這些序列化處理的信息可以通過讀取文件或者攔截網絡傳輸的方式訪問,因而爲了保護信息安全(比如密碼信息)或者有某個特定的子對象不想被Java序列化機制自動保存,就可以使用transient關鍵字關閉序列化。
如上源碼可知ArrayList底層是維護了一個Object數組實現的,有三個默認構造函數,使用無參構造函數時,Object數組默認容量是10,當長度不夠時,自動增長0.5倍,查詢速度快。對於增刪操作,因爲牽扯到元素的拷貝(增加時,會申請一個更大的數組,將原有數組的元素拷貝至新的數組),速度慢。 
示例

/*
* 思路:創建一個新的集合,將舊集合中的元素一次複製到新集合,複製的前提是新集合中不存在該元素,就可以刪除重複的
*/
import java.util.ArrayList;
import java.util.Iterator;
 
class Book{
int id;
String name;// 名字
 
public Book(int id, String name) {
this.id = id;
this.name = name;
}
 
@Override
public String toString() {
return "{ 書號:"+ this.id+" 書名:"+ this.name+" }";
}
 
@Override
public boolean equals(Object obj) {
Book book =(Book)obj;
return this.id==book.id;
}
}
 
// 需求: 編寫一個函數清除集合中重複元素。 如果書號是一樣就視爲重複元素。 要求: 遍歷集合元素的時候必須使用迭代器。 java編程思想和java探祕書號一樣,第二個java探祕會被清除
public class Test {
public static void main(String[] args) {
ArrayList list= new ArrayList();
list.add(new Book(110,"java編程思想"));
list.add(new Book(220,"java核心技術"));
list.add(new Book(330,"JVM虛擬機"));
list.add(new Book(110,"java探祕"));
 
ArrayList list2 = clearRepeat(list);
System.out.println("新集合的元素是:"+ list2);
}
 
public static ArrayList clearRepeat(ArrayList list){
//創建一個新的集合
ArrayList newList = new ArrayList();
//獲取迭代器
Iterator it = list.iterator();
while(it.hasNext()){
Book book = (Book) it.next(); //從舊集合中獲取的元素
if(!newList.contains(book)){
//如果新集合沒有包含該書籍,那麼就存儲到新集合中
newList.add(book);
}
}
return newList;
}
}

實現類LinkedList使用

LinkedList實現類內部實現主要是以指針方式連接的,相鄰的兩個元素地址不一樣相鄰。此實現不是同步的。如果多個線程同時訪問一個鏈接列表,而其中至少一個線程從結構上修改了該列表,則它必須 保持外部同步。 
查看LinkedList函數定義實現:

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

LinkedList 是一個繼承於AbstractSequentialList的雙向鏈表。它也可以被當作堆棧、隊列或雙端隊列進行操作。 
LinkedList 實現了: 
List 接口,能對它進行隊列操作。 
Deque 接口,即能將LinkedList當作雙端隊列使用,支持在兩端插入和移除元素。 
Cloneable接口,即覆蓋了函數clone(),能克隆。 
java.io.Serializable接口,這意味着LinkedList支持序列化,能通過序列化去傳輸。

實例

import java.util.LinkedList;
/*
使用LinkedList模擬堆棧的數據結構存儲方式
1:棧 : 主要是用於實現堆棧數據結構的存儲方式。
先進後出
push()
pop()
2:隊列: 主要是爲了讓你們可以使用LinkedList模擬隊列數據結構的存儲方式。
先進先出
offer()
poll()
*/
class StackList{
LinkedList list;
 
public StackList(){
list = new LinkedList();
}
 
//進棧
public void add(Object o){
list.push(o);
}
 
//彈棧 : 把元素刪除並返回。
public Object pop(){
return list.pop();
}
 
//獲取元素個數
public int size(){
return list.size();
}
}
//使用LinkedList模擬隊列的存儲方式
class TeamList{
LinkedList list;
public TeamList(){
list = new LinkedList();
}
 
public void add(Object o){
list.offer(o);
}
 
public Object remove(){
return list.poll();
}
 
//獲取元素個數
public int size(){
return list.size();
}
}
public class LinkedListTest {
public static void main(String[] args) {
TeamList list= new TeamList();
list.add("張三");
list.add("李四");
list.add("王五");
 
int size = list.size();
for(int i = 0 ; i<size ; i++){
System.out.println(list.remove());
}
}
}

發佈了45 篇原創文章 · 獲贊 17 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章