zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    读书笔记——吴军《态度》
    JZYZOJ1237 教授的测试 dfs
    NOI1999 JZYZOJ1289 棋盘分割 dp 方差的数学结论
    [JZYZOJ 1288][洛谷 1005] NOIP2007 矩阵取数 dp 高精度
    POJ 3904 JZYZOJ 1202 Sky Code 莫比乌斯反演 组合数
    POJ2157 Check the difficulty of problems 概率DP
    HDU3853 LOOPS 期望DP 简单
    Codeforces 148D. Bag of mice 概率dp
    POJ3071 Football 概率DP 简单
    HDU4405 Aeroplane chess 飞行棋 期望dp 简单
  • 原文地址:https://www.cnblogs.com/three-fighter/p/13052945.html
Copyright © 2011-2022 走看看