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

Java集合框架——List接口的更多相关文章
- Java集合框架——Set接口
		
第三阶段 JAVA常见对象的学习 集合框架--Set接口 List集合的特点是有序的,可重复的,是不是存在这一种无序,且能保证元素唯一的集合呢?(HashSet )这就涉及到我们今天所要讲的Set集合 ...
 - Java集合框架之接口Collection源码分析
		
本文我们主要学习Java集合框架的根接口Collection,通过本文我们可以进一步了解Collection的属性及提供的方法.在介绍Collection接口之前我们不得不先学习一下Iterable, ...
 - Java集合框架Map接口
		
集合框架Map接口 Map接口: 键值对存储一组对象 key不能重复(唯一),value可以重复 常用具体实现类:HashMap.LinkedHashMap.TreeMap.Hashtable Has ...
 - Java集合框架顶层接口collectiion接口
		
如何使用迭代器 通常情况下,你会希望遍历一个集合中的元素.例如,显示集合中的每个元素. 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合 ...
 - Java集合框架——Map接口
		
第三阶段 JAVA常见对象的学习 集合框架--Map集合 在实际需求中,我们常常会遇到这样的问题,在诸多的数据中,通过其编号来寻找某一些信息,从而进行查看或者修改,例如通过学号查询学生信息.今天我们所 ...
 - JAVA集合框架 - Map接口
		
Map 接口大致说明(jdk11): 整体介绍: 一个将键映射到值的(key-value)对象, 键值(key)不能重复, 每个键值只能影射一个对象(一一对应). 这个接口取代了Dictionary类 ...
 - Java集合框架的接口和类层次关系结构图
		
Collection和Collections的区别 首先要说的是,"Collection" 和 "Collections"是两个不同的概念: 如下图所示,&qu ...
 - Java集合框架之接口Iterator
		
简述 Iterator迭代器的定义:迭代器(Iterator)模式,又叫做游标(Cursor)模式.GOF给出的定义是,提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象 ...
 - Lambda表达式和Java集合框架
		
本文github地址 前言 我们先从最熟悉的Java集合框架(Java Collections Framework, JCF)开始说起. 为引入Lambda表达式,Java8新增了java.util. ...
 
随机推荐
- 【题解】[Nwerc 2006]escape -C++
			
Description 给出数字N(1<=N<=10000),X(1<=x<=1000),Y(1<=Y<=1000),代表有N个敌人分布一个X行Y列的矩阵上 矩形的 ...
 - DOS窗口启动tomact,运用startup.bat/shutdown.bat命令启动/关闭tomcat
			
设置CATALINA_HOME环境变量1.CATALINA_HOME是TOMCAT安装路径的别名,目的是为了方便使用TOMCAT2.计算机>属性>环境变量, 新建环境变量.变量名为CATA ...
 - mkdir/rmdir/install/mktemp
			
mkdir rmdir很有趣,如果加上p选项,如果删除空目录后,其父目录是空,则一并删除,所以如果都是空的,那么就会全家删 a用户不能修改b用户的文件,但是却可以删除 install 创建文件并赋权 ...
 - Bzoj 3942: [Usaco2015 Feb]Censoring(kmp)
			
3942: [Usaco2015 Feb]Censoring Description Farmer John has purchased a subscription to Good Hooveske ...
 - P1582 倒水,P2158 [SDOI2008]仪仗队——数学,二进制
			
有n个瓶子,里面都有一升水,但是只想保留k个瓶子,只能两个瓶子里面的水体积相等时才能倒在一个瓶子里:不能丢弃有水的瓶子:瓶子容量无限: 问需要购买几个额外的瓶子才能满足条件: 因为每个瓶子一开始只有一 ...
 - 内存管理2-@class关键字
			
Review: 给对象发送消息,进行相应的计数器操作. Retain消息:使计数器+1,改方法返回对象本身 Release消息:使计数器-1(并不代表释放对象) retainCount消息:获得对象当 ...
 - Geos判断点是否在多边形内
			
使用的geo版本是3.5.1 #include <iostream> #include "geos.h" using namespace std; GeometryFa ...
 - 6.3 MRUnit写Mapper和Reduce的单元测试
			
1.1 MRUnit写单元测试 作用:一旦MapReduce项目提交到集群之后,若是出现问题是很难定位和修改的,只能通过打印日志的方式进行筛选.又如果数据和项目较大时,修改起来则更加麻烦.所以,在将 ...
 - Linux设备驱动程序 之 工作队列
			
工作队列可以把工作推后,交给一个内核线程去执行–这个下半部分总是会在进程上下文中执行:通过工作队列执行的代码占尽进程上下文的优势:最重要的是工作队列允许重新调度甚至睡眠: 在工作队列和软中断/task ...
 - Understanding the ASP.NET MVC Execution Process
			
https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/overview/understanding-the-asp ...