• Java容器深入浅出之List、ListIterator和ArrayList


    List是Collection接口的子接口,表示的是一种有序的、可重复元素的集合。

    List接口的主要实现类ArrayList和Vector,底层都是维护了一套动态的,可扩展长度的Object[]数组,通过initialCapacity参数来动态地调整长度。因此,相比较父接口Collection所提供的公共增删改方法,List接口及实现类也定义了通过索引来增删查改元素,或者基于元素查找索引的方法。更一般地,ArrayList中的元素可以为null。

    List及List新增的ListIterator接口

    List接口的定义方法如下

     1 public class TestList {
     2 
     3     @SuppressWarnings("unlikely-arg-type")
     4     public static void main(String[] args) {
     5         
     6         List<String> books = new ArrayList<>();
     7         //List集合添加元素的顺序是有序的
     8         books.add(new String("资本论"));
     9         books.add(new String("***宣言"));
    10         books.add(new String("家庭私有制和国家的起源"));
    11         System.out.println(books);
    12         //add和addAll分别在指定索引处添加元素或另一个集合
    13         books.add(1, "德意志意识形态");
    14         books.forEach(str -> System.out.println(str));
    15         //使用Lambda表达式对List进行排序
    16         books.sort((o1, o2) -> (o1.length() - o2.length()));
    17         System.out.println(books);
    18         //删除指定索引的元素
    19         books.remove(2);
    20         System.out.println(books);
    21         //通过指定索引返回元素(==根据HashCode来判断,此处返回false)
    22         System.out.println(books.get(0) ==new String("资本论"));
    23         //通过indexOf来返回指定元素所在的索引位置
    24         //indexOf通过元素的equals方法来判断, 只要是true就返回对应的索引
    25         System.out.println(books.indexOf(new String("德意志意识形态")));
    26         //通过索引改变元素
    27         books.set(1, new String("神圣家族"));
    28         //返回子集合[1,3), 不改变原集合
    29         System.out.println(books.subList(1, 3));
    30         
    31         //使用Lambda表达式使用每个字符的长度替代原集合的元素
    32         books.replaceAll(ele -> ele.length() + "");
    33         //因为A对象equals方法恒返回true,所以集合会在第一次比较中直接删除第一个元素
    34         books.remove(new A());
    35         System.out.println(books);
    36         //同样的,继续删除第一个元素
    37         books.remove(new A());
    38         System.out.println(books.size());
    39         
    40     }
    41 
    42 }
    43 
    44 class A{
    45     //定义A类对象的equals方法恒返回true
    46     public boolean equals(Object obj) {
    47         return true;
    48     }
    49 }

    与Set集合不同,List集合新增了一个继承Iterator接口的子接口ListIterator接口,可以实现反向迭代和增加元素的功能。

     1 /*
     2  * 与Collection集合的Iterator接口不同, List额外提供一个ListIterator接口(继承了Iterator接口), 增加了如下三个方法:
     3  * 1. hasPrevious():是否还有上一个元素
     4  * 2. previous():返回上一个元素
     5  * 3. add():增加一个元素
     6  */
     7 public class ListIteratorTest {
     8 
     9     public static void main(String[] args) {
    10         
    11         String[] books = {
    12                 "资本论","德意志意识形态","***宣言"
    13         };
    14         List<String> booksList = new ArrayList<>();
    15         for(int i=0; i<books.length;i++) {
    16             booksList.add(books[i]);
    17         }
    18         ListIterator<String> lit = booksList.listIterator();
    19         System.out.println("====下面开始正向迭代====");
    20         while(lit.hasNext()) {
    21             System.out.println(lit.next());
    22             lit.add("----分隔符----");
    23         }
    24         System.out.println("====下面开始反向迭代====");
    25         while(lit.hasPrevious()) {
    26             System.out.println(lit.previous());
    27         }
    28         
    29     }
    30 
    31 }

    ArrayList和Vector

    如前所述,ArrayList和Vector底层维护了一个动态可变的对象数组。如果创建对象时不指定容量值,会有一个默认的数组长度10。更一般地,可以通过在创建对象时指定容量值:

    1. void ensureCapacity(int minCapacity):将List集合数组长度增加到minCapacity。如可提前知道元素个数,可以赋值长度,以减少频繁扩容所带来的性能开销。

    2. void trimToSize():调整数组长度至当前元素的个数,以节省空间。

    ArrayList与Vector相比较,需要注意以下几点:

    1. ArrayList是线程不安全的,因此性能较高;Vector是线程安全的,但性能较差;后面的博文会介绍如果通过Collection提供的工具类,使ArrayList线程安全。

    2. Vector及其子类Stack,是非常古旧的Java集合,并不建议使用。Stack子类所实现的栈功能,也可以通过ArrayDeque来实现。

    固定长度的List

    数组的工具类Arrays自带一个asList(Object... o)方法,可以将数组或指定数量的对象转换为List,不过需要注意一点:

    该类是Arrays类的内部类ArrayList的实例,是固定长度的,相当于数组,只能用于遍历,不能增加和删除里面的元素。

     1 public class TestArrayList {
     2 
     3     public static void main(String[] args) {
     4         
     5         List<String> list = Arrays.asList("AA", "BB", "CC");
     6         //显示类的类型为java.util.Arrays$ArrayList
     7         System.out.println(list.getClass());
     8         
     9         list.forEach(System.out::println);
    10         //以下会抛出运行时异常java.lang.UnsupportedOperationException
    11         list.add("DD");
    12 
    13     }
    14 
    15 }

    线性表的性能选择

    一般来说,基于数组的ArrayList在随机访问中性能较好;基于链表的LinkedList在插入、删除中性能较好。但在一般使用中,ArrayList总体性能占优,因此使用非常广泛。

    1. 如果需要遍历List元素,ArrayList建议使用随机访问方法;对于LinkedList,建议使用Iterator迭代器

    2. 如果需要经常插入、删除大量数据的List集合,可以考虑使用LinkedList

  • 相关阅读:
    iOS如何隐藏状态栏,包括网络标志、时间标志、电池标志等
    xcrun: error: active developer path
    我们很少有机会看到一个人的所有面
    默妹(二)
    Bootstrap3的响应式缩略图幻灯轮播效果设计
    纯CSS3实现图片展示特效
    解决div设置浮动,高度消失
    解决css设置背景透明,文字不透明
    从零开始学习jQuery (六) jquery中的AJAX使用
    如何利用开源思想开发一个SEO友好型网
  • 原文地址:https://www.cnblogs.com/leoliu168/p/9907962.html
Copyright © 2020-2023  润新知