• Java Review (二十七、集合----- List 集合)


    @


    List 集合代表一个元素有序 、可重复的集合,集合中每个元素都有其对应的顺序索引 。 List 集合允许使用重复元素 , 可以通过索引来访问指定位置的集合元素 。 List 集合默认按元素的添加顺序设置元素的索引 。


    Java8 改进的List 接口和Listlterator 接口

    相比较父接口 Collection,由于 List 是有序集合 , 因此 List 集合里增加 了一些根据索引来操作集合元素的方法。

    • void add(int index, Object element): 将元素 element 插入到 List 集合的 index 处 。
    • boolean addAll(int index, Collection c): 将集合 c 所包含的所有元素都插入到 List 集合的 index处。
    • Object get(int index): 返回集合 index 索引处的元素。
    • int indexOf(Object 0): 返回对象 。 在 List 集合中第 一次出现的位置索引。
    • int lastlndexOf(Object 0): 返 回 对象 。 在 List 集合中最后 一 次出现的位置索引 。
    • Object remove(int index): 删除并返回 index 索引处的元素 。
    • Object set(int index, Object element): 将 index 索引处的元素替换成 e lement 对象,返回被替换的旧元素 。
    • List subList(int fromIndex, int toIndex): 返回从索引 fromlndex (包含)到索引 to Index (不包含)处所有集合元素组成的子集合。

    所有 的 List 实现类都可以调用这些方法来操作集合元素。与 Set 集合相比, List 增加了根据索引来插入、替换和删除集合元素 的方法。除此之外 , Java 8 还为 List 接口添加了如下两个默认方法 :

    • void replaceAll(UnaryOperator operator): 根据 operator 指定的计算规则重新设置 List 集合的所有元素。
    • void sort(Comparator c): 根据 Comparator 参数对 List 集合的元素排序 。

    下面程序示范了 List 集合的常规用法:

    ListTest.java

    public class ListTest
    {
    	public static void main(String[] args)
    	{
    		List books = new ArrayList();
    		// 向books集合中添加三个元素
    		books.add(new String("轻量级Java EE企业应用实战"));
    		books.add(new String("疯狂Java讲义"));
    		books.add(new String("疯狂Android讲义"));
    		System.out.println(books);
    		// 将新字符串对象插入在第二个位置
    		books.add(1 , new String("疯狂Ajax讲义"));
    		for (int i = 0 ; i < books.size() ; i++ )
    		{
    			System.out.println(books.get(i));
    		}
    		// 删除第三个元素
    		books.remove(2);
    		System.out.println(books);
    		// 判断指定元素在List集合中位置:输出1,表明位于第二位
    		System.out.println(books.indexOf(new String("疯狂Ajax讲义"))); //①
    		//将第二个元素替换成新的字符串对象
    		books.set(1, new String("疯狂Java讲义"));
    		System.out.println(books);
    		//将books集合的第二个元素(包括)
    		//到第三个元素(不包括)截取成子集合
    		System.out.println(books.subList(1 , 2));
    	}
    }
    

    运行结果:

    在这里插入图片描述①行代码处,程序试图返回新字符串对象在 List集合中的位置,实际上 List 集合中并未包含该字符串对象 。 因为 List 集合添加宇符串对象时 ,添加的是通过 new 关键宇创建的新字符串对象,①行代码处也是通过 new 关键宇创建的新字符串对象,两个字符串显然不是同一个对象,但 List 的 indexOf 方法依然可以返回 1 。

    List 判断两个对象相等只要通过 equals()方法比较返回 true 即可 。


    ListTest2.java

    class A
    {
    	public boolean equals(Object obj)
    	{
    		return true;
    	}
    }
    public class ListTest2
    {
    	public static void main(String[] args)
    	{
    		List books = new ArrayList();
    		books.add(new String("轻量级Java EE企业应用实战"));
    		books.add(new String("疯狂Java讲义"));
    		books.add(new String("疯狂Android讲义"));
    		System.out.println(books);
    		// 删除集合中A对象,将导致第一个元素被删除
    		books.remove(new A());     // ①
    		System.out.println(books);
    		// 删除集合中A对象,再次删除集合中第一个元素
    		books.remove(new A());     // ②
    		System.out.println(books);
    	}
    }
    

    运行结果:
    在这里插入图片描述执行①行代码时 ,程序试图删除一个 A 对象 , List 将会调用该A对象的equals()方法依次与集合元素进行比较,如果该 equalsO方法 以某个集合元素作为参数时返回 true , List将会删除该元素——A 类重写了 equalsO方法 , 该方法总是返回 true。所 以每次从 List 集合中删除 A 对象时 ,总是删除 List 集合中的第一个元素 。

    与 Set 只提供了 一个 iterator()方法不同, List 还额外提供了 一个 listIterator()方法,该方法返回 一个Listlterator 对象, ListIterator 接口继承了Iterator 接口,提供了专门操作 List 的方法 。 ListIterator 接口在Iterator 接口基础上增加了如下方法 。

    • boolean hasPreviousO: 返回该法代器关联的集合是否还有上一个元素 。
    • Object previous(): 返回该迭代器的上一个元素。
    • void add(Object 0): 在指定位置插入一个元素 。

    API:java.util.List

    API:java.util.ListIterator


    ArrayList 和 Vector 实现类


    ArrayList结构图

    在这里插入图片描述
    ArrayList 和 Vector 类都是基于数组实现的 List 类,所以 ArrayList 和 Vector 类封装了一个动态的、允许再分配的 Object[]数组 。 ArrayList 或 Vector 对象使用 initialCapacity 参数来设置该数组的长度, 当向 ArrayList 或 Vector 中添加元素超出了该数组的长度时,它们的 initialCapacity 会自动增加 。

    ArrayList构造方法

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            // 如果传入的初始容量大于0,就新建一个数组存储元素
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            // 如果传入的初始容量等于0,使用空数组EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            // 如果传入的初始容量小于0,抛出异常
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        }
    }
    

    对于通常的编程场景,程序员无须关心 ArrayList 或 Vector 的 initialCapacity 。 但如果向ArrayList或 Vector 集合中添加大 量 元素时,可使用ensureCapacity(int minCapacity) 方法一次性地增加initialCapacity 。 这可以减少重分配 的 次数 ,从而提高性能 。

    如果开始就知道 ArrayList 或 Vector 集合需要保存多少个元素,则可以在创建它们时就指定initialCapacity 大小 。 如果创建空的 ArrayList 或 Vector 集合时不指定 initialCapacity 参数 ,则 Object[] 数组的长度默认为 10 。

    ArrayList属性

    /**
     * 默认容量
     */
    private static final int DEFAULT_CAPACITY = 10;
    
    /**
     * 空数组,如果传入的容量为0时使用
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
    /**
     * 空数组,传传入容量时使用,添加第一个元素的时候会重新初始为默认容量大小
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    /**
     * 存储元素的数组
     */
    transient Object[] elementData; // non-private to simplify nested class access
    
    /**
     * 集合中元素的个数
     */
    private int size;
    

    除此之外,ArrayList 和 Vector 还提供了如下两个方法来重新分配 Object[]数组:

    • void ensureCapacity(int minCapacity): 将 ArrayList 或 Vector 集合的 Object[]数组长度增加大于或等于 minCapacity 值。
    • void trimToSize(): 调整 ArrayList 或 Vector 集合 的 Object[]数组长度为 当前元素 的个数 。 调用该方法可减少 ArrayList 或 Vector 集合对象占用 的存储空间 。

    ArrayList 和 Vector 在用法上几乎完全相同 ,Vector十分古老,那时候 Java 还没有提供系统的集合框架,所以 Vector 里提供了 一 些方法名很长的方法。

    除此之外, ArrayList 和 Vector 的 显著区别是 :
    ArrayList 是线程不安全的,当多个线程访问同一个ArrayList 集合时,如果有超过一个线程修改了 ArrayList 集合,则程序必须于动保证该集合的同步性;
    Vector 集合则是线程安全的,无须程序保证该集合的同步性。因为 Vector 是线程安全的,所以 Vector的性能比 ArrayList 的性能要低 。

    API:java.util.ArrayList

    API:java.util.Vector


    LinkedList 实现类


    LinkedList结构图

    在这里插入图片描述
    LinkedList 类是 List 接口的实现类 一它是一 个 List 集合 ,可以根据索引来随机访问集合中的元素 。

    除此之外, LinkedList 还实现了 Deque 接口,可以被当成双端队列来使用,还可以被当成"栈"来使用 。

    下面程序简单示范了 LinkedList 集合的用法:

    LinkedListTest.java

    public class LinkedListTest
    {
    	public static void main(String[] args)
    	{
    		LinkedList books = new LinkedList();
    		// 将字符串元素加入队列的尾部
    		books.offer("疯狂Java讲义");
    		// 将一个字符串元素加入栈的顶部
    		books.push("轻量级Java EE企业应用实战");
    		// 将字符串元素添加到队列的头部(相当于栈的顶部)
    		books.offerFirst("疯狂Android讲义");
    		// 以List的方式(按索引访问的方式)来遍历集合元素
    		for (int i = 0; i < books.size() ; i++ )
    		{
    			System.out.println("遍历中:" + books.get(i));
    		}
    		// 访问、并不删除栈顶的元素
    		System.out.println(books.peekFirst());
    		// 访问、并不删除队列的最后一个元素
    		System.out.println(books.peekLast());
    		// 将栈顶的元素弹出“栈”
    		System.out.println(books.pop());
    		// 下面输出将看到队列中第一个元素被删除
    		System.out.println(books);
    		// 访问、并删除队列的最后一个元素
    		System.out.println(books.pollLast());
    		// 下面输出:[轻量级Java EE企业应用实战]
    		System.out.println(books);
    	}
    }
    

    LinkedList 与 ArrayList 的实现机制完全不同:

    • ArrayList 内部以数组的形式来保存集合中的元素 , 因此随机访问集合元素时有较好的性能;
    • 而 LinkedList 内部以链表的形式来保存集合中的元素,因此随机访问集合元素时性能较差,但在插入、删除元素时性能比较出色(只需改变指针所指的地址即可)。


    双向链表

    在这里插入图片描述
    从链表删除元素

    在这里插入图片描述

    API:java.util.LinkedList








    参考
    【1】:《疯狂Java讲义》
    【2】:《Java核心技术 卷一》
    【3】:Java技术驿站:【死磕 Java 集合】— ArrayList源码分析
    【4】:方志朋的专栏:Java基础:Java容器之ArrayList
    【5】:Java技术驿站:【死磕 Java 集合】— LinkedList源码分析
    【6】:方志朋的专栏:Java基础:Java容器之LinkedList
    【7】:廖雪峰的官方网站:使用List

  • 相关阅读:
    hdu 5045 Contest
    hdu 4068 SanguoSHA
    TSP 旅行商问题(状态压缩dp)
    haoi2015 树上操作
    noi 2015 软件包管理器(树链剖分)
    zjoi2008 树链剖分
    读入优化
    动态规划类型总结
    有关Rujia Liu 动态规划的·一些总结
    输入优化
  • 原文地址:https://www.cnblogs.com/three-fighter/p/13052945.html
Copyright © 2020-2023  润新知