当前位置:   article > 正文

List 子类_list有哪些子类

list有哪些子类


List的特点:有序,有索引,可重复

List子类有:ArrayList,LinkedList,Vector

ArrayList:异步,非线程安全(随机访问效率高)

LinkedList:异步, 非线程安全(随机插入、删除效率高)

Vector    :同步,线程安全(因为同步的要求会影响执行的效率,所以如果不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步而带来的不必要的性能开销)

1.ArrayList

ArrayList是List子类,可以直接通过对象的多态性为List接口实例化。此类的定义如下:

public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
 
从定义中可以发现ArrayList类继承了AbstractList类。AbstractList类的定义如下: 

public abstract class AbstractList<E>
extends AbstractCollection<E>
implements List<E>

此类实现了List接口,所以可以直接使用ArrayList为List接口实例化。下面通过一些实例操作为读者讲解List接口中主要方法的使用。

(1)实例操作一:向集合中增加元素

要想完成此类操作,可以直接使用Collection接口中定义的两个方法。

增加一个元素:public boolean add(E o)。

增加一组元素:public boolean addAll(Collection<? extends E> c)。

也可以使用List扩充的add()方法在指定位置处增加元素。

在指定位置处添加元素:public void add(int index,E element)。

范例:验证增加数据的操作

  1. package com.list.demo;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.List;
  5. public class Demo_Test1 {
  6. public static void main(String[] args) {
  7. List<String> allList = null; // 定义List对象
  8. Collection<String> allCollection = null; // 定义Collection对象
  9. allList = new ArrayList<String>(); // 实例化List对象,只能是String类型
  10. allCollection = new ArrayList<String>(); // 实例化Collection,只能是String类型
  11. allList.add("Hello"); // 从Collection继承的方法
  12. allList.add(0, "World"); // 此方法为List扩充的方法
  13. System.out.println(allList); // 输出集合中的内容
  14. allCollection.add("GGG"); // 增加数据
  15. allCollection.add("www.mldn.cn"); // 增加数据
  16. allList.addAll(allCollection); // 从Collection继承的方法,增加一组对象
  17. allList.addAll(0, allCollection); // 此方法是List自定义的,增加一组对象
  18. System.out.println(allList); // 输出对象,调用toString()方法
  19. }
  20. }

程序运行结果:

 
 
 
  1. [World, Hello]  
  2. [GGG, www.mldn.cn, World, Hello, GGG, www.mldn.cn] 

从程序的运行结果中可以发现,使用List中的add(int index,E element)方法可以在集合中的指定位置增加元素,而其他的两个add()方法只是在集合的最后进行内容的追加。

 (2)实例操作二:删除元素

在类集中提供了专门的删除元素的方法,Collection和List接口都分别定义了删除数据的方法。

Collection定义的方法

每次删除一个对象:public boolean remove(Object o)。

每次删除一组对象:public boolean removeAll(Collection<?> c)。

List扩展的方法

删除指定位置的元素:public E remove(int index)。

范例:删除对象

 

  1. package com.list.demo;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class Demo_Test1 {
  5. public static void main(String[] args) {
  6. List<String> allList = null; // 声明List对象
  7. allList = new ArrayList<String>(); // 实例化List对象,只能是String类型
  8. allList.add("Hello"); // 增加元素
  9. allList.add(0, "World"); // 此方法为List扩展的增加方法
  10. allList.add("MLDN"); // 增加元素
  11. allList.add("www.mldn.cn"); // 增加元素
  12. allList.remove(0); // 删除指定位置的元素
  13. allList.remove("Hello"); // 删除指定内容的元素
  14. System.out.println(allList); // 输出对象,调用toString()方法
  15. }
  16. }


程序运行结果:

 
 
  1. [MLDN, www.mldn.cn] 

在集合中增加完数据后,可以通过下标或对象的方式直接对集合中的元素进行删除。

U提示:关于使用remove(Object o)方法删除对象的说明。

在集合中可以插入任意类型的对象,在本程序中是以String类的对象为例,所以在使用remove(Object o)方法删除时可以直接删除;而对于自定义的类如果要通过此种方式删除,则必须在类中覆写Object类的equals()及hashCode()方法。这两个方法的使用在随后的章节中将为读者介绍。

(3)实例操作三:输出List中的内容

在Collection接口中定义了取得全部数据长度的方法size(),而在List接口中存在取得集合中指定位置元素的操作get(int index),使用这两个方法即可输出集合中的全部内容。

范例:输出全部元素

  1. package com.list.demo;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class Demo_Test1 {
  5. public static void main(String[] args) {
  6. List<String> allList = null; // 定义List接口对象
  7. allList = new ArrayList<String>(); // 实例化List对象,只能使String类型
  8. allList.add("Hello"); // 增加元素
  9. allList.add("Hello"); // 增加元素
  10. allList.add(0, "World"); // 增加元素
  11. allList.add("MLDN"); // 增加元素
  12. allList.add("www.mldn.cn"); // 增加元素
  13. System.out.print("由前向后输出:"); // 信息输出
  14. for (int i = 0; i < allList.size(); i++) // 循环输出集合内容
  15. {
  16. System.out.print(allList.get(i) + "、"); // 通过下标取得集合中的元素
  17. }
  18. System.out.print("\n由后向前输出:");
  19. for (int i = allList.size() - 1; i >= 0; i--) // 循环输出集合内容
  20. {
  21. System.out.print(allList.get(i) + "、"); // 通过下标取得集合中的元素
  22. }
  23. }
  24. }


程序运行结果:

 
 
  1. 由前向后输出:World、Hello、Hello、MLDN、www.mldn.cn、  
  2. 由后向前输出:www.mldn.cn、MLDN、Hello、Hello、World、 

从程序的运行结果中可以看出,在List集合中数据增加的顺序就是输出后的顺序,本身顺序不会发生改变。

(4)实例操作四:将集合变为对象数组

在Collection中定义了toArray()方法,此方法可以将集合变为对象数组,但是由于在类集声明时已经通过泛型指定了集合中的元素类型,所以在接收时要使用泛型指定的类型。

范例:将集合变为对象数组

  1. package com.list.demo;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class Demo_Test1 {
  5. public static void main(String[] args) {
  6. List<String> allList = null; // 声明List对象
  7. allList = new ArrayList<String>(); // 实例化List对象,只能是String类型
  8. allList.add("Hello"); // 增加元素
  9. allList.add(0, "World"); // 增加元素
  10. allList.add("MLDN"); // 增加元素
  11. allList.add("www.mldn.cn"); // 增加元素
  12. String str[] = allList.toArray(new String[] {}); // 指定的泛型类型
  13. System.out.print("指定数组类型:"); // 信息输出
  14. for (int i = 0; i < str.length; i++) {
  15. // 输出字符串数组中的内容
  16. System.out.print(str[i] + "、");
  17. // 输出每一个元素
  18. }
  19. System.out.print("\n返回对象数组:");
  20. // 信息输出
  21. Object obj[] = allList.toArray();
  22. // 直接返回对象数组
  23. for (int i = 0; i < obj.length; i++) {
  24. // 循环输出对象数组内容
  25. String temp = (String) obj[i];
  26. // 每一个对象都是String类 型实例
  27. System.out.print(temp + "、");
  28. // 输出每一个元素
  29. }
  30. }
  31. }


程序运行结果:

 
 
  1. 指定数组类型:World、Hello、MLDN、www.mldn.cn、  
  2. 返回对象数组:World、Hello、MLDN、www.mldn.cn、 

(5)实例操作五:集合的其他相关操作

在List中还存在截取集合、查找元素位置、判断元素是否存在、集合是否为空等操作。下面直接测试以上的操作。

范例:测试其他操作

  1. package com.hehe.coco;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class Test_Demo_1
  5. {
  6. public static void main(String[] args)
  7. {
  8. List<String> allList = null;// 声明List对象
  9. allList = new ArrayList<String>(); // 实例化List对象,只能是 String类型
  10. System.out.println("集合操作前是否为空?" + allList.isEmpty());
  11. allList.add("Hello");// 增加元素
  12. allList.add(0, "World");// 增加元素
  13. allList.add("MLDN");// 增加元素
  14. allList.add("www.mldn.cn");// 增加元素
  15. System.out.println(allList.contains("Hello") ? "\"Hello\"字符串存在!" : "\"Hello\"字符串不存在!");
  16. List<String> allSub = allList.subList(2, 3);// 取出里面的部分集合
  17. System.out.println(allSub);
  18. System.out.print("集合截取:");
  19. for (int i = 0; i < allSub.size(); i++)// 截取部分集合
  20. {
  21. System.out.print(allSub.get(i) + "、");
  22. }
  23. System.out.println("");
  24. System.out.println("MLDN字符串的位置:" + allList.indexOf("MLDN"));
  25. System.out.println("集合操作后是否为空?" + allList.isEmpty());
  26. }
  27. }

程序运行结果:

  
  
  1. 集合操作前是否为空?true 
  2. "Hello"字符串存在! 
  3. [MLDN] 
  4. 集合截取:MLDN、  
  5. MLDN字符串的位置:2 
  6. 集合操作后是否为空?false 
List集合在刚刚实例化之后因为还有为其增加内容,所以在使用isEmpty()方法时返回的结果是true,表示集合是空的,之后向集合中增加了4个元素,所以程序的最后再使用此方法判断时就返回false,表示集合中已经存在内容。在程序中使用contains()方法判断集合中是否存在指定的元素,如果存在,则输出存在的信息;反之,输出不存在的信息。在集合中也可以使用subList()方法取出指定的子集合。

2.LinkekList

LinkedList也和ArrayList一样实现了List接口,但是它执行插入和删除操作时比ArrayList更加高效,因为它是基于链表的。基于链表也决定了它在随机访问方面要比ArrayList逊色一点,所以使用LinkedList时不要用get方法,即使LinkedList的元素个数只有很少的几个。也要避免使用,养成好习惯,免得犯错。
LinkedList底层的数据结构是基于双向循环链表的,且头结点中不存放数据,如下

既然是双向链表,那么必定存在一种数据结构——我们可以称之为节点,节点实例保存业务数据,前一个节点的位置信息和后一个节点位置信息,如下图所示:

(1)LinkedList和ArrayList性能测试

这里针对于LinkedList和ArrayList 的插入和随机访问性能做了如下测试,测试代码如下:

1.LinkedList插入和随机访问性能测试

  1. package com.LinkedList.demo;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. public class LinkedList_Demo_1 {
  5. public static void main(String[] args) {
  6. int size = 2000000;// 200万次循环
  7. List<String> list = new LinkedList<String>();// 实例化LinkedList对象
  8. long addStartTime = System.currentTimeMillis();// add开始时间
  9. for (int i = 0; i < size; i++)// 200万次循环
  10. {
  11. list.add("Just some test data");// 增加元素
  12. }
  13. long addEndTime = System.currentTimeMillis();// add结束时间
  14. System.out.println("LinkedList添加200万条数据,耗时:" + (addEndTime - addStartTime)
  15. + "\t毫秒");// 打印添加200万条数据所消耗的时间
  16. long queryStartTime = System.currentTimeMillis();// query开始时间
  17. for (int i = 0; i < size; i++)// 循环200万次
  18. {
  19. list.get(i);// 取出当前循环的元素
  20. if (i % 100000 == 0)// 当元素每循环到10万条时,记录消耗毫秒数
  21. {
  22. long queryEndTime = System.currentTimeMillis();// query结束时间
  23. System.out.println("LinkedList查询到第: " + i + "条数据,本次耗时"
  24. + (queryEndTime - queryStartTime) + " 毫秒");// 打印查询200万条数据所消耗的时间
  25. queryStartTime = System.currentTimeMillis();// 初始化下一次query开始时间
  26. }
  27. }
  28. }
  29. }
程序运行结果:

LinkedList添加200万条数据,耗时:2218 毫秒
LinkedList查询到第: 0条数据,本次耗时0  毫秒
LinkedList查询到第: 100000条数据,本次耗时13121  毫秒
LinkedList查询到第: 200000条数据,本次耗时61236  毫秒
LinkedList查询到第: 300000条数据,本次耗时102181  毫秒
LinkedList查询到第: 400000条数据,本次耗时148209  毫秒
LinkedList查询到第: 500000条数据,本次耗时183442  毫秒
......

后面几条记录用省略号代替来了,由于后面的结果实在太慢的,等下去也没有意义,从这里可以看出LinkedList查询的结果是非常的慢,所以要避免使用LinkedList的get方法。

2.ArrayLis插入和随机访问性能测试

  1. package com.ArrayList.demo;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class ArrayList_Demo_1 {
  5. public static void main(String[] args) {
  6. int size = 2000000;// 200万次循环
  7. List<String> list = new ArrayList<String>();//实例化ArrayList对象
  8. long addStartTime = System.currentTimeMillis();// add开始时间
  9. for (int i = 0; i < size; i++)// 200万次循环
  10. {
  11. list.add("Just some test data");// 增加元素
  12. }
  13. long addEndTime = System.currentTimeMillis();// add结束时间
  14. System.out.println("ArrayList添加200万条数据,耗时:"
  15. + (addEndTime - addStartTime) + " 毫秒");// 打印添加200万条数据所消耗的时间
  16. long queryStartTime = System.currentTimeMillis();// query开始时间
  17. for (int i = 0; i < size; i++)// 循环200万次
  18. {
  19. list.get(i);// 取出当前循环的元素
  20. if (i % 100000 == 0)// 当元素每循环到10万条时,记录消耗毫秒数
  21. {
  22. long queryEndTime = System.currentTimeMillis();// query结束时间
  23. System.out.println("ArrayList查询到第: " + i + "条数据,本次耗时"
  24. + (queryEndTime - queryStartTime) + " 毫秒");// 打印查询200万条数据所消耗的时间
  25. queryStartTime = System.currentTimeMillis();// 初始化下一次query开始时间
  26. }
  27. }
  28. }
  29. }
程序运行结果:

ArrayList添加200万条数据,耗时:59  毫秒
ArrayList查询到第: 0条数据,本次耗时0  毫秒
ArrayList查询到第: 100000条数据,本次耗时10  毫秒
ArrayList查询到第: 200000条数据,本次耗时0  毫秒
ArrayList查询到第: 300000条数据,本次耗时1  毫秒
ArrayList查询到第: 400000条数据,本次耗时0  毫秒
ArrayList查询到第: 500000条数据,本次耗时0  毫秒
ArrayList查询到第: 600000条数据,本次耗时1  毫秒
ArrayList查询到第: 700000条数据,本次耗时0  毫秒
ArrayList查询到第: 800000条数据,本次耗时0  毫秒
ArrayList查询到第: 900000条数据,本次耗时1  毫秒
ArrayList查询到第: 1000000条数据,本次耗时0  毫秒
ArrayList查询到第: 1100000条数据,本次耗时0  毫秒
ArrayList查询到第: 1200000条数据,本次耗时0  毫秒
ArrayList查询到第: 1300000条数据,本次耗时1  毫秒
ArrayList查询到第: 1400000条数据,本次耗时0  毫秒
ArrayList查询到第: 1500000条数据,本次耗时0  毫秒
ArrayList查询到第: 1600000条数据,本次耗时0  毫秒
ArrayList查询到第: 1700000条数据,本次耗时1  毫秒
ArrayList查询到第: 1800000条数据,本次耗时0  毫秒
ArrayList查询到第: 1900000条数据,本次耗时0  毫秒

结果很清晰,使用ArrayList的get方法随机访问对象中的元素所消耗的时间是很短的。在很多地方会看到LinkedList比ArrayList插入的效率较快,这样说是不严谨的,比如上面的测试:

ArrayList添加200万条数据,耗时:59 毫秒
LinkedList添加200万条数据,耗时:2218 毫秒

这样看起来ArrayList插入效率比LinkedList高,这样说也不严谨的。我理解是有序的插入是ArrayList效率高,无序的插入LinkedList效率高。


3.Vector

Vector非常类似ArrayList,但是Vector是同步的。ArrayList会比Vector快,因为ArrayList是非同步的,如果设计涉及到多线程,还是用Vector比较好一些 。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。

  1. package com.Vector.demo;
  2. import java.util.Iterator;
  3. import java.util.Vector;
  4. public class VectorDemo {
  5. /**
  6. * Vector的使用。包括Vector的创建、向Vector中添加元素、从Vector中删除元素、
  7. * 统计Vector中元素的个数和遍历Vector中的元素。
  8. */
  9. public static void main(String[] args) {
  10. Vector<String> v = new Vector<String>(4);// 实例化Vector对象
  11. v.add("Test1");// 添加元素
  12. v.add("Test0");// 添加元素
  13. v.add("Test2");// 添加元素
  14. v.add("Test0");// 添加元素
  15. v.add("Test2");// 添加元素
  16. System.err.println(v);
  17. /**
  18. * 删除元素
  19. */
  20. v.remove("Test0"); // 删除指定内容的元素(这里是删除第一个出现的该元素)
  21. v.remove(0); // 按照索引下标删除元素
  22. /**
  23. * 获得已有元素的个数
  24. */
  25. int size = v.size();
  26. System.out.println("size:" + size);
  27. /**
  28. * 遍历元素
  29. */
  30. for (int i = 0; i < v.size(); i++)
  31. {
  32. System.out.println(v.get(i));
  33. }
  34. /**
  35. * 迭代元素
  36. */
  37. Iterator<String> iterator = v.iterator();
  38. while (iterator.hasNext())
  39. {
  40. System.err.println(iterator.next());
  41. }
  42. }
  43. }

程序运行结果:
[Test1, Test0, Test2, Test0, Test2]
size:3
Test2
Test0
Test2
Test2
Test0
Test2

Vector 类提供了实现可增长数组的功能,随着更多元素加入其中,数组变的更大。在删除一些元素之后,数组变小。 




























声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/77353
推荐阅读
相关标签
  

闽ICP备14008679号