资讯专栏INFORMATION COLUMN

Java集合框架——List接口

褰辩话 / 2186人阅读

摘要:第三阶段常见对象的学习集合框架接口按照集合框架的继承体系,我们先从中的接口开始学习一概述及功能演示概述在中充当着一个什么样的身份呢有序的也称为序列实现这个接口的用户以对列表中每个元素的插入位置进行精确地控制。线程不安全,效率高。

第三阶段 JAVA常见对象的学习 集合框架——List接口

按照集合框架的继承体系,我们先从Collection中的List接口开始学习
(一) 概述及功能(ArrayList演示) (1) 概述

List在Collection中充当着一个什么样的身份呢?——有序的 collection(也称为序列)

实现这个接口的用户以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 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()方法

基本功能

//将指定的元素插入列表(可选操作)
void add(E e) 

//返回 true如果遍历正向列表,列表迭代器有多个元素
boolean hasNext() 

//返回列表中的下一个元素,并且前进光标位置
E next() 

//从列表中删除由 next()或 previous()返回的最后一个元素(可选操作) 
void remove() 

//用 指定的元素替换由 next()或 previous()返回的最后一个元素(可选操作)
void set(E e) 

特有功能

//获取上一个元素
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 elements()    --  iterator()
(四) List案例练习
下面的案例题目个别来源于网络,我们来整理,书写一下。
案例(一):集合嵌套存储和遍历元素的案例

需求:

我们班有学生,每一个学生是不是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList

但是呢,我们旁边是不是还有班级,每个班级是不是也是一个 ArrayList

而我现在有多个ArrayList。也要用集合存储,怎么办呢 ?

按照我们的想法就是这个样子的:ArrayList>

案例 (二): 获取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 a = new ArrayList();
        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 a = new ArrayList();
        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 array = new ArrayList();

    @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技术的公众号:理想二旬不止

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75014.html

相关文章

  • Java™ 教程(集合接口

    集合接口 核心集合接口封装了不同类型的集合,如下图所示,这些接口允许独立于其表示的细节来操纵集合,核心集合接口是Java集合框架的基础,如下图所示,核心集合接口形成层次结构。 showImg(https://segmentfault.com/img/bVbntJW?w=402&h=146); Set是一种特殊的Collection,SortedSet是一种特殊的Set,依此类推,另请注意,层次结构...

    elisa.yang 评论0 收藏0
  • Java集合框架——Map接口

    摘要:第三阶段常见对象的学习集合框架集合在实际需求中,我们常常会遇到这样的问题,在诸多的数据中,通过其编号来寻找某一些信息,从而进行查看或者修改,例如通过学号查询学生信息。面试题和的区别是单列集合的顶层接口,有子接口和。 第三阶段 JAVA常见对象的学习 集合框架——Map集合 showImg(https://segmentfault.com/img/remote/1460000019683...

    princekin 评论0 收藏0
  • Java 集合框架

    摘要:基础部分集合框架接口接口泛型所有集合类都位于包下。集合框架的知识总结集合框架总结接口的使用集合框架总结类的排序问题声明常量的两种方法遍历的四种方法泛型当我们把一个对象放入集合中后,系统会把所有集合元素都当成类的实例进行处理。 Java 基础部分——集合框架 Collection 接口 Map 接口 泛型 所有集合类都位于java.util包下。集合中只能保存对象(保存对象的...

    Flink_China 评论0 收藏0
  • 集合框架知识系列01 总体框架

    摘要:集合工具包是在包中,实现了数据结构数组栈链表队列映射和集合。集合主要可以划分为个部分列表集合映射工具类迭代器枚举类和。集合的框架图如下图片来源集合顶层接口主要有和。和都是集合遍历相关接口,是特有的遍历工具接口 Java集合工具包是在java.util.*包中,实现了数据结构:数组、栈、链表、队列、映射和集合。Java集合主要可以划分为4个部分:List列表、Set集合、Map映射、工具...

    honhon 评论0 收藏0
  • 集合框架源码学习之ArrayList

    摘要:用户自己指定容量创建大小的数组创建空数组默认构造函数,其默认初始容量为构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。以正确的顺序返回该列表中的元素的迭代器。此方法充当基于阵列和基于集合的之间的桥梁。 目录: 0-0-1. 前言 0-0-2. 集合框架知识回顾 0-0-3. ArrayList简介 0-0-4. ArrayList核心源码 0-0-5. Ar...

    BLUE 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<