List集合简单总结
参考书籍java疯狂讲义所做的学习总结。我相信我还会回来的!
一、概要:List集合是一个元素有序,可重复的集合,该接口是Collection接口的子接口。List接口下接口的实现类有,ArrayList、LinkedList、Vector,其中Vector年龄较大(1.0版本就存在了)。
二、List接口中常用的方法
》void add(int index,Object element):将元素element插入到集合的index处。
》boolean addAll(int index,Collection c):将集合c所包含的元素都插入到List集合的index处。
》Object get(int index):返回集合index处的索引处的元素。
》int indexOf(Object o):返回对象o在List集合中第一次出现的位置索引。
》int lastIndexOf(Object o):返回对象o在List集合中最后一次出现的索引。
》Object remove(int index):删除并返回index索引处的元素。
》Object set(int index,Object element):将index索引处的元素替换为element对象,返回新元素。
》List subList(int fromIndex,int toIndex):返回从索引fromIndex(包含)到toIndex(不包含)处所有集合元素组成的子集合。
部分用法如下:
- import java.util.ArrayList;
- import java.util.Vector;
- public class ListTest {
- public static void main(String[] args) {
- //创建集合对象
- ArrayList<String> list1 = new ArrayList<String>();
- //add(E e):添加元素
- list1.add("hello");
- list1.add("world");
- list1.add("java");
- //add(int index,E element):在指定的索引处添加一个元素
- list1.add(1, "android");
- System.out.println("array:"+list1);
- //========================================================
- //创建集合对象
- ArrayList<String> array = new ArrayList<String>();
- //添加元素
- array.add("hello");
- array.add("world");
- array.add("java");
- //public E get(int index):返回指定索引处的元素
- System.out.println("get:"+array.get(0));
- System.out.println("get:"+array.get(1));
- System.out.println("get:"+array.get(2));
- //public int size():返回集合中的元素的个数
- System.out.println("size:"+array.size());
- //public boolean remove(Object o):删除指定的元素,返回删除是否成功
- System.out.println("remove:"+array.remove("world"));//true
- System.out.println("remove:"+array.remove("world"));//false
- //public E remove(int index):删除指定索引处的元素,返回被删除的元素
- System.out.println("remove:"+array.remove(0));
- //public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
- System.out.println("set:"+array.set(0, "android"));
- //输出
- System.out.println("array:"+array);
- }
- }
三、遍历List集合的三种方式
- public class ListSearchTest {
- public static void main(String[] args) {
- List list = new ArrayList<>();
- list.add(0);
- list.add(1);
- list.add(2);
- list.add(3);
- //No1:for循环遍历
- for (int i = 0; i < list.size(); i++) {
- System.out.println(list.get(i));
- }
- System.out.println("==============================");
- //No2:foreach遍历
- for (Object object : list) {
- System.out.println(object);
- }
- System.out.println("==============================");
- //No3:使用Iterator迭代器
- Iterator iterator = list.iterator();
- while(iterator.hasNext()){
- System.out.println(iterator.next());
- }
- }
- }
关于迭代器Iterator的使用:Iterator接口也是java集合框架的成员,但它与Collection,Map集合不一样,Collection集合和Map集合主要用户装对象,而Iterator主要用于遍历,Iterator本身病不提供盛装对象的能力;还有一点需要注意的是,当时用Iterator遍历Collection集合元素时,只有通过Iterator的romove方法删除上一次next方法返回的集合元素才可以,否则的话,会引发java.util.ConcuurentModdificationException异常。
三、ArrayList的使用以及存储原理
ArrayList和Vector是基于数组实现的List类,所以AyyayList和Vector类封装了一个动态的、允许再分配的Object数组。ArrayList或Vector对象使用initialCapacity参数设置数组的长度,当向ArrayList和Vector中添加元素超出该数组的长度时,他们的initialCapacity会自动增加。数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组的增长大约是其原容量的1.5倍。如果向ArrayList或Vector集合中添加大量元素时,可使用ensureCapacity(int X)方法一次性地增加initialCapacity.可减少重分配的次数,从而提高性能。(摘自疯狂java讲义)
关于具体ArrayList的实现原理,推荐前辈博客:https://www.cnblogs.com/ITtangtang/p/3948555.html
四、LinkedList的使用原理
1.LinkedList是一个双向链表,它也可以被当作堆栈、队列或双端队列进行操作。既然其底层的数据结构是链表,必然每个节点中的存储都是:前一个节点的位置信息,节点数据和后一个节点的位置信息。正是因为此结构,所以在进行增删元素的时候效率特别高,不需要像ArrayList那样还要按索引查找,在进行增加,删除元素,然后还需要更新索引结构。LinkedList在进行增删的时候,只需要修改上一个元素的后节点信息和下一个元素的前节点信息即可。但是在查询的时候就慢了,它只能依次访问集合中的每个元素,找不到的话,就根据链表继续向下走,去访问下一个元素。
2.使用LinkedList模拟队列:
- /*
- *LinkeList:链表集合.
- */
- public class LinkedListTest1 {
- public static void main(String[] args) {
- LinkedList<Object> ll = new LinkedList<>();
- ll.addFirst("a");
- ll.addFirst("b");
- ll.addFirst("c");
- ll.addFirst("d");
- System.out.println(ll); // 倒序的效果. 输出[d,c,b,a]
- Object first = ll.getFirst() ;
- System.out.println(first); //d
- Object last = ll.getLast();
- System.out.println(last); //a
- }
- }
- 3.使用LinkedList模拟栈:
- public class LinkedListTest2 {
- public static void main(String[] args) {
- //创建 LinkedList
- LinkedList<Object> ll = new LinkedList<>();
- //a先压栈,b,c以此压栈
- ll.push("a");
- System.out.println(ll);//[a]
- ll.push("b");
- System.out.println(ll);//[b,a]
- ll.push("c");
- System.out.println(ll); //[c,b,a]
- //弹栈,先进后出
- System.out.println(ll.pop()); //c
- System.out.println(ll);//[b,a]
- System.out.println(ll.pop()); //b
- }
- }
五、线程安全问题
ArrayList是线程不安全的集合,当有多个线程访问同一个Arraylist的集合时,如果有超过一个线程修改了ArrayList集合,则必须手动保证该集合的同步性。使用Conllections类中提供的syschronizedXXX()方法,该方法将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时带来的线程安全问题。
- public class CollectionTest {
- public static void main(String[] args) {
- //创建4个同步的集合对象
- Collection c = Collections.synchronizedCollection(new ArrayList());
- List<Object> list = Collections.synchronizedList(new ArrayList<Object>());
- Set<Object> set = Collections.synchronizedSet(new HashSet<Object>());
- Map<Object, Object> map = Collections.synchronizedMap(new HashMap<Object,Object>());
- }
- }
六、ArrayList和LinkedList性能比较
1.ArrayList做查询比较快,但是增删的时候比较满。当插入或删除元素时,还要涉及数组元素的移动等内存操作。
2.LinkedList做增删比较快,但是查询慢。LinkedList使用双向链表实现存储,形成一个按序号索引的线性结构,与数组存储的方式相比,按序号索引数据需要进行前向或后向遍历,但是插入数据的时候,只需要记录本项的前后项即可,所以插入较快,删除同样。