您现在的位置是:首页 > 文章详情

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

日期:2018-11-04点击:416

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

原文链接:https://yq.aliyun.com/articles/669550
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章