Java集合框架——List接口

第三階段 JAVA常見對象的學習

集合框架——List接口

按照集合框架的繼承體系,咱們先從Collection中的List接口開始學習

(一) 概述及功能(ArrayList演示)

(1) 概述

List在Collection中充當着一個什麼樣的身份呢?——有序的 collection(也稱爲序列) java

實現這個接口的用戶以對列表中每一個元素的插入位置進行精確地控制。用戶能夠根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。與 set 不一樣,列表一般容許重複的元素。數據庫

(2)List集合功能

A:基本功能:(繼承而來)
//添加功能
boolean add(E e)向集合中添加一個元素
    
//刪除功能
void clear():移除集合中的全部元素
boolean remove(Object o):從集合中移除指定的元素
boolean removeAll(Collection<?> c):從集合中移除一個指定的集合元素(有一個就返回true)

//獲取功能
Iterator iterator():就是用來獲取集合中每個元素。

//判斷功能
boolean isEmpty():判斷集合是否爲空
boolean contains(Object o):判斷集合中是否包含指定元素
boolean containsAll(Collection<?> c):判斷集合中是否包含指定的一個集合中的元素

//長度功能
int size():獲取集合中元素的個數

//集合轉換爲數組
Object[] toArray()
B:特有功能:
//添加功能:在指定位置添加元素
void add(int index,Object element)
   
//獲取功能:獲取指定位置的元素
Object get(int index)
   
//列表迭代器:List集合特有的迭代器
ListIterator listIterator()
   
//刪除功能:根據索引刪除元素,返回被刪除的元素
Object remove(int index)
   
//修改功能:根據索引修改元素,返回被修飾的元素。
Object set(int index,Object element)
A:add() 使用方法:

咱們仍是先寫一個List遍歷字符串的代碼數組

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Demo1 {
    public static void main(String[] args) {
        //建立集合對象
        List list = new ArrayList();


        //存儲元素
        list.add("I");
        list.add("love");
        list.add("you");
        list.add("❤");
        list.add("❤");

        //遍歷集合
        Iterator it = list.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            System.out.print(s + " ");
        }
    }
}

//運行結果
I love you ❤ ❤

經過這段代碼咱們能夠看到,List集合的特色——有序(存儲和去取出的元素一直),可重複安全

咱們再使用List存儲學生對象並遍歷看看網絡

//Student 自行補充

//StudentDemo類
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class StudentDemo {
    public static void main(String[] args) {
        List list = new ArrayList();

        Student s1 = new Student("張三", 20);
        Student s2 = new Student("李四", 30);
        Student s3 = new Student("王五", 40);

        list.add(s1);
        list.add(s2);
        list.add(s3);

        Iterator it = list.iterator();
        while (it.hasNext()) {
            Student s = (Student) it.next();
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}

//運行結果
張三---20
李四---30
王五---40

//Student s = (Student)it.next();       
//it.next()返回的是Object類型。
//(Student)it.next();是將Object類型強制轉換成Student類型。
//這樣纔可以調用getName()方法和getAge()方法。
B:add() 使用方法:
package cn.bwh_02_List.ArrayList;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class StudentDemo {
    public static void main(String[] args) {
        List list = new ArrayList();

        Student s1 = new Student("張三", 20);
        Student s2 = new Student("李四", 30);
        Student s3 = new Student("王五", 40);

        list.add(s1);
        list.add(s2);
        list.add(s3);
        //迭代器遍歷
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Student s = (Student) it.next();
            System.out.println(s.getName() + "---" + s.getAge());
        }

        //利用List的功能遍歷
        for (int x = 0; x < list.size(); x++){
            Student s = (Student) list.get(x);
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}

上面幾個實例中,咱們使用了Iterator迭代器遍歷,下面咱們介紹一種特別的迭代器數據結構

C: 列表迭代器:

ListIterator listIterator():列表迭代器:List集合特有的迭代器併發

列表迭代器繼承於Iterator迭代器,能夠直接使用hasNext() 和next()方法框架

基本功能dom

//將指定的元素插入列表(可選操做)
void add(E e) 

//返回 true若是遍歷正向列表,列表迭代器有多個元素
boolean hasNext() 

//返回列表中的下一個元素,而且前進光標位置
E next() 

//從列表中刪除由 next()或 previous()返回的最後一個元素(可選操做) 
void remove() 

//用 指定的元素替換由 next()或 previous()返回的最後一個元素(可選操做)
void set(E e)

特有功能ide

//獲取上一個元素
Object previous()

//判斷是否有元素
boolean hasPrevious()

列表迭代器的好處是相比Iterator提供了更多的方法,而且能夠實現正向遍歷,才能逆向遍歷,因此通常來講意義不大。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class Demo1 {
    public static void main(String[] args) {
        //建立集合對象
        List list = new ArrayList();

        //存儲元素
        list.add("I");
        list.add("love");
        list.add("you");
        list.add("❤");
        list.add("❤");

        ListIterator lit= list.listIterator();
        //正向遍歷
        while(lit.hasNext()){
            String s = (String)lit.next();
            System.out.print(s + " ");
        }

        System.out.println();
        //逆向遍歷
        while (lit.hasPrevious()) {
            String s = (String) lit.previous();
            System.out.print(s + " ");

        }
    }
}

//運行結果
I love you ❤ ❤ 
❤ ❤ you love I

(二) 併發修改異常問題

我建立了一個集合,而且遍歷它,使用if語句判斷 是否集合中存在"love"這個字符串,若存在,就增長一個"❤"元素,咱們先順着這個思路寫一下代碼:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
 *  併發修改異常
 */
public class Demo2 {
    public static void main(String[] args) {
        //建立集合對象
        List list = new ArrayList();

        //存儲元素
        list.add("I");
        list.add("love");
        list.add("you");

        Iterator it = list.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            if ("love".equals(s)) {
                list.add("❤");
            }
            System.out.println(s);
        }
    }
}

//運行結果(節選)
Exception in thread "main" java.util.ConcurrentModificationException

咱們貼出JDK中對這個異常的解釋:

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.

當不容許這樣的修改時,能夠經過檢測到對象的併發修改的方法來拋出此異常。

(1) 緣由解釋:

當咱們對集合進行遍歷的時候,咱們會獲取當前集合的迭代對象

//List爲例,獲取集合的迭代對象
Iterator it = list.iterator();

這個迭代對象中,封裝了迭代器的方法與集合自己的一些方法,當咱們在迭代中使用集合自己的add方法的時候,就產生了ConcurrentModificationException異常,通俗的說就是,在判斷成功後,集合中元素增長了,可是迭代器不清楚,因此就報錯,若是迭代器中含有這一種方法(假設),咱們是用迭代器添加元素就不會有問題了。

針對這個問題,咱們給出兩個解決方案

(2) 解決方案:

##### 方式1:迭代器迭代元素,迭代器修改元素

咱們假想若是Iterator迭代器中有添加功能就行了,但很遺憾並無,可是它的子接口ListIterator卻擁有這個功能

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Demo2 {
    public static void main(String[] args) {
        //建立集合對象
        List list = new ArrayList();


        //存儲元素
        list.add("I");
        list.add("love");
        list.add("you");

        ListIterator lit = list.listIterator();
        while (lit.hasNext()) {
            String s = (String) lit.next();
            if ("love".equals(s)) {
                lit.add("❤");
            }
            System.out.print(s + " ");
        }
    }
}

//運行結果
I love you
2:集合遍歷元素,集合修改元素(普通for)
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Demo2 {
    public static void main(String[] args) {
        //建立集合對象
        List list = new ArrayList();

        //存儲元素
        list.add("I");
        list.add("love");
        list.add("you");

        for (int x = 0; x < list.size(); x++){
            String s = (String)list.get(x);
            if ("love".equals(s)){
                list.add("❤");
            }
            System.out.print(s + " ");
        }
    }
}

//運行結果
I love you ❤

二者都可以解決併發修改異常的問題,可是經過運行結果也能夠看出,方法一添加後,在本次遍歷中不會輸出添加的結果,而方法二卻能夠。

補充:加強for循環實現將集合進行遍歷,也產生了併發修改異常,這是由於加強for在底層也是調用的集合自己的remove

(3) 總結:

在迭代器遍歷時,若是須要對集合進行增刪操做時,要調用迭代器自己的remove方法,或者選擇使用普通for進行遍歷

(三) Vector (過期,不推薦)

特有功能
    a:添加
        public void addElement(E obj)        --    add()
    b:獲取
        public E elementAt(int index)        --    get()
        public Enumeration<E> elements()    --  iterator()

(四) List案例練習

下面的案例題目個別來源於網絡,咱們來整理,書寫一下。

案例(一):集合嵌套存儲和遍歷元素的案例

需求:

咱們班有學生,每個學生是否是一個對象。因此咱們可使用一個集合表示咱們班級的學生。ArrayList<Student>

可是呢,咱們旁邊是否是還有班級,每一個班級是否是也是一個 ArrayList<Student>

而我如今有多個ArrayList<Student>。也要用集合存儲,怎麼辦呢 ?

按照咱們的想法就是這個樣子的:ArrayList<ArrayList<Student>>

案例 (二): 獲取10個1-20之間的隨機數,要求不能重複

package cn.bwh_02_List.ArrayList.RandomDemo;

import java.util.ArrayList;
import java.util.Random;
/*
 *  分析:
 *      A:建立產生隨機數的對象
 *      B:建立一個存儲隨機數的集合
 *      C:定義一個統計變量,從0開始
 *      D:判斷統計遍歷是否小於10
 *          小於10:
 *              若不存在:就添加,同時統計變量++
 *              若不存在:則不做處理
 *          大於10;
 *              不做處理
 *      E:遍歷集合
 */
public class ArrayDemo {
    public static void main(String[] args) {
        Random r = new Random();
        ArrayList<Integer> a = new ArrayList<Integer>();
        int count = 0;
        while (count < 10) {
            int number = r.nextInt(20) + 1;
            if (!a.contains(number)){
                a.add(number);
                count++;
            }
        }

        for (Integer i : a){
            System.out.print(i + " ");
        }

    }
}

案例 (三) 鍵盤錄入多個數據

鍵盤錄入多個數據,以0結束,要求在控制檯輸出這多個數據中的最值

package cn.bwh_02_List.ArrayList.InputMore;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

/*
 *  分析:
 *      A:建立鍵盤錄入數據對象
 *      B:鍵盤錄入多個數據,不知道數量,因此用集合存儲
 *      C:以0結束——只要鍵盤錄入的數據是0,就不繼續錄入數據了
 *      D:把集合轉成數組
 *      E:對數組排序
 *      F:獲取該數組中的最大索引的值
 */
public class AeeayDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入數據");
        ArrayList<Integer> a = new ArrayList<Integer>();
        while (true) {
            int number = sc.nextInt();
            if (number != 0) {
                a.add(number);
            } else {
                break;
            }
        }

        Integer[] i = new Integer[a.size()];
        a.toArray(i);
        Arrays.sort(i);
        System.out.println(i[i.length - 1]);

    }
}

案例 (五) 登陸註冊案例(使用集合)

package cn.bwh.pojo;

/**
 * 這是用戶基本描述類
 *
 * @author BWH_Steven
 * @version v1.0
 */

public class User {
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package cn.bwh.dao;

import cn.bwh.pojo.User;

/**
 * 這是針對用戶進行操做的接口
 *
 * @author BWH_Steven
 * @version v1.0
 */
public interface UserDao {
    /**
     * 這是用戶登陸功能
     *
     * @param username 用戶名
     * @param password 密碼
     * @return 返回登陸是否成功
     */
    public abstract boolean isLogin(String username, String password);

    /**
     * 這是用戶註冊功能
     *
     * @param user 要註冊的用戶信息
     */
    public abstract void regist(User user);
}

由於註冊的時候極可能還要填寫
例如地址,性別,愛好等等信息(而登陸功能的時候每每只須要用戶名和密碼),因此這個註冊功能傳進來的參數過多,所以用對象代替過多的參數,也就是說,經過傳遞對象(User user)包含衆多信息避免了直接傳遞String username,password等等變量過多的問題

package cn.bwh.dao.impl;

import cn.bwh.dao.UserDao;
import cn.bwh.pojo.User;

import java.util.ArrayList;

/**
 * 這是用戶操做的具體實現類(集合類)
 *
 * @author BWH_Steven
 * @version v1.0
 */
public class UserDaoImpl implements UserDao {
    //爲了多個集合可以使用同一個集合,就把集合定義爲成員變量
    //爲了避免讓外人看到,用private
    private static ArrayList<User> array = new ArrayList<User>();

    @Override
    public boolean isLogin(String username, String password) {

        //遍歷集合,獲取每個用戶,而且判斷用戶的用戶名和密碼是否和傳遞過來的匹配
        boolean flag = false;

        for (User u : array) {
            if (u.getUsername().equals(username) && u.getPassword().equals(password)) ;
            flag = true;
            break;
        }

        return flag;
    }

    @Override
    public void regist(User user) {
        //把用戶信息存入集合內
        array.add(user);
    }
}
package cn.bwh.test;

import cn.bwh.dao.UserDao;
import cn.bwh.dao.impl.UserDaoImpl;
import cn.bwh.pojo.User;

import java.util.Scanner;

/**
 * 用戶測試類
 *
 * @author BWH_Steven
 * @version v1.0
 */
public class UserTest {
    public static void main(String[] args) {
        //爲了可以到主界面
        while (true) {
            System.out.println("------------初次見面,請多指教------------");
            System.out.println("1 登陸");
            System.out.println("2 註冊");
            System.out.println("3 退出");
            System.out.println("請輸入你的選擇");

            Scanner sc = new Scanner(System.in);
            //爲了後面錄入信息方便,全部的數據錄入均使用字符串接受
            //Switch語句的多個地方要使用,對象就定義到外面
            String choicString = sc.nextLine();

            //調用註冊功能,使用多態
            UserDao ud = new UserDaoImpl();

            switch (choicString) {
                case "1":
                    System.out.println("----------------登陸系統----------------");
                    System.out.println("請輸入用戶名");
                    String username = sc.nextLine();
                    System.out.println("請輸入密碼");
                    String password = sc.nextLine();

                    //調用登陸功能
                    boolean flag = ud.isLogin(username, password);
                    if (flag) {
                        System.out.println("登錄成功");
                        System.exit(0);
                        //break; 這裏break結束的是switch
                    } else {
                        System.out.println("用戶名或者密碼錯誤,登陸失敗");
                    }
                    break;
                case "2":
                    System.out.println("--------------新用戶註冊---------------");
                    System.out.println("請輸入用戶名");
                    String newUsername = sc.nextLine();
                    System.out.println("請輸入密碼");
                    String newPassword = sc.nextLine();

                    //把用戶名和密碼封裝到一個類中
                    User user = new User();
                    user.setUsername(newUsername);
                    user.setPassword(newPassword);

                    ud.regist(user);
                    System.out.println("註冊成功");
                    break;
                case "3":
                default:
                    System.out.println("謝謝使用,感謝你曾經來過過");
                    System.exit(0);
                    break;
            }

        }
    }
}
小結:

dao層主要鏈接數據庫,封裝增刪改查的數據庫語句

daoimpl是實現dao層方法的接口,因此能夠把具體實現的方法寫在daoimpl中,dao層只寫方法名就能夠。

Pojo表明簡單的Java對象

(五) List子類的特色(總結)

ArrayList:

​ 底層數據結構是數組查詢快增刪慢

線程不安全效率高

Vector:

​ 底層數據結構是數組查詢快增刪慢

線程安全效率低

LinkedList:

​ 底層數據結構是鏈表查詢慢增刪快

線程不安全效率高

使用具體狀況

保證安全:Vector

​ (即便要安全,也不用這個,後面有替代的)

不保證安全:ArrayList或者LinkedList

查詢多:ArrayList

增刪多:LinkedList

結尾:

若是內容中有什麼不足,或者錯誤的地方,歡迎你們給我留言提出意見, 蟹蟹你們 !^_^

若是能幫到你的話,那就來關注我吧!(系列文章均會在公衆號第一時間更新)

在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤

一個堅持推送原創Java技術的公衆號:理想二旬不止

相關文章
相關標籤/搜索