Java集合框架——List接口

第三阶段 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<E> elements()    --  iterator()

(四) List案例练习

下面的案例题目个别来源于网络,我们来整理,书写一下。

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

需求:

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

但是呢,我们旁边是不是还有班级,每个班级是不是也是一个 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<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技术的公众号:理想二旬不止

原文地址:https://www.cnblogs.com/ideal-20/p/11085684.html

时间: 2024-10-30 11:52:48

Java集合框架——List接口的相关文章

Java集合框架——Set接口

第三阶段 JAVA常见对象的学习 集合框架--Set接口 List集合的特点是有序的,可重复的,是不是存在这一种无序,且能保证元素唯一的集合呢?(HashSet )这就涉及到我们今天所要讲的Set集合 Set可以理解为行为不同的Collection (一) 概述及功能 (1) 概述 Collection List -- 有序(存储顺序和取出顺序一致),可重复 Set -- 无序(存储顺序和取出顺序不一致),唯一 我们首先要清楚有序无序,到底是什么意思? 集合所说的序,是指元素存入集合的顺序,当元

Java集合框架顶层接口collectiion接口

如何使用迭代器 通常情况下,你会希望遍历一个集合中的元素.例如,显示集合中的每个元素. 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对象,实现了Iterator 接口或ListIterator接口. 迭代器,使你能够通过循环来得到或删除集合的元素.ListIterator 继承了Iterator,以允许双向遍历列表和修改元素. 序号 迭代器方法描述 1 使用 Java Iterator这里通过实例列出Iterato

java集合框架--List接口

1.List接口概述 有序的集合序列.此接口的用户可以对列表中的每个元素的插入位置进行精确的控制.用户可以根据元素的索引(在列表中的位置)访问元素,并搜索列表中的元素. 与Set接口不同,列表通常允许重复的元素. 2.List案例 存储字符串并遍历 package com; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /**  * 存储字符串并遍历  *  */ public clas

Java集合框架的接口和类层次关系结构图

%E7%94%A8groovy%E8%84%9A%E6%9C%AC%E8%BF%9B%E8%A1%8C%E6%AF%8F%E6%97%A5%E5%B7%A5%E4%BD%9C%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96groovy http://auto.315che.com/zhiyue/qa23760388.htm?437o http://auto.315che.com/jingyi/qa23872297.htm http://auto.315che.com/xi

Java集合框架总结(4)——List接口的使用

Java集合框架总结(4)--List接口的使用 List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引.List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素. 1.List接口和ListIterator接口 List作为Collection接口的子接口,可以使用Collection接口里的全部方法.List是有序集合,所以List集合里增加了一些根据索引来操作集合元素的方法: void add(int index, Object element):将元素element插

Java集合框架总结(5)——Map接口的使用

Java集合框架总结(5)--Map接口的使用 Map用于保存具有映射关系的数据(key-vlaue).Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较总是返回false Map中包含了一个keySet()方法,用于返回Map所以key组成的Set集合. Map集合与Set集合元素的存储形式很像,如Set接口下有HashSet.LinkedHashSet.SortedSet(接口).TreeSet.EnumSet等实现类和子接口,而Map接口下则有HashMa

Java集合框架中List接口的简单使用

Java集合框架可以简单的理解为一种放置对象的容器,和数学中的集合概念类似,Java中的集合可以存放一系列对象的引用,也可以看做是数组的提升,Java集合类是一种工具类,只有相同类型的对象引用才可以放到同一个集合中,否则是不能放进去的: 集合可以对元素进行简单快速的查找.插入.删除操作 某些集合可以有<key value>映射的关系 数组的长度是固定的,而集合的长度是跟随元素的个数动态变化的,灵活性和扩展性都比数组更加优越 数组只能存放基本类型的数据,而集合存放的是对象引用类型的 数组只能通过

Java集合框架之List接口

在上一篇Java集合框架之Collection接口中我们知道List接口是Collection接口的子接口,List接口对Collection进行了简单的扩充,List接口中的元素的特点为有序,可重复,允许null值,因为List继承了Collection接口,所以继承自Collection接口中的方法不再赘述,从List接口中的方法来看,List接口主要是增加了面向位置的操作,允许在指定位置上对集合中的元素进行操作,同时增加了一个能够双向遍历线性表的新列表迭代器ListIterator.下面介

Java集合框架中Map接口的使用

在我们常用的Java集合框架接口中,除了前面说过的Collection接口以及他的根接口List接口和Set接口的使用,Map接口也是一个经常使用的接口,和Collection接口不同,Map接口并不是线性的存放对象的引用,Map接口提供了一种映射关系,所有的元素都是以键值对(Entry类型对象实例)的方式存储的,所以能够根据key快速查找value,key是映射关系的索引,value是key所指向的对象,注意,这里的value不是一个数值,而是一个对象的引用,Java集合框架的元素均是指对象!