List接口(动态数组)
List集合类中元素_有序且可重复_
ArrayList(重要)
- 作为List接口的主要实现类
- 线程不安全的,效率高
- 底层使用Object[] elementData数组存储
ArrayList的源码分析
jdk7
- 构造器 - ArrayList list = new ArrayList(); - 底层创建了长度为10的Object[]数组elementData
 
- 添加数据 - list.add(123) - 相当于elementData[0] = new Integer(123)
- 底层的数组长度为10,添加元素个数小于10时,正常添加元素
- 添加的元素个数大于10后(底层elementData数组容量不够),则需要扩容,默认扩容为原来容量的1.5倍(相当于新造一个数组,长度为原来长度的1.5倍)。同时需要将原来数组的数据复制到新的数组中
 
结论:建议使用带参的构造器(避免在中间时扩容)
ArrayList list = new ArrayList(int capacity)
jdk8
- 构造器 - ArrayList list = new ArrayList(); - 底层Object[] elementData初始化为{},并没有创建长度为10的数组
 
- 添加数据 - list.add(123) - 第一次add()时,底层才创建了长度为10的数组,并将数据123添加到elementData[0]位置上
- 后续的添加与扩容操作与jdk7相同
 
结论
- jdk7中的ArrayList的对象的创建类似于单例模式中的饿汉式
- jdk8中的ArrayList的对象的创建类似于单例模式中的懒汉式。延迟了数组的创建,节省内存
LinkedList
- 对于频繁的插入、删除操作,使用此类效率比ArrayList高
- 底层使用双向链表存储 
LinkedList的源码分析
LinkedList list = new LinkedList();
内部声明了Node类型的first和last属性,默认值为null
list.add(123);
将123封装到Node中,创建了Node对象
其中Node定义为(源码),体现了LinkedList双向链表的特征:
private static class Node<E> {
        E item;
        LinkedList.Node<E> next;
        LinkedList.Node<E> prev;
        Node(LinkedList.Node<E> prev, E element, LinkedList.Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
Vector(不常用)
- 作为List接口的古老实现类
- 线程安全的、效率低
- 底层使用Object[] elementData数组存储
Vector源码分析
- jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组
- 默认扩容为原来数组长度的2倍
三者异同
相同点
三个类都实现了List接口,存储数据的特点相同(有序、可重复的数据)
不同点
- 底层不同
- 不同情况下效率不同
- 线程安全问题
List接口中常用的方法
Collection中的方法都可用
- add(int index , Object eles) - 在index位置开始,将eles中的所有元素添加进来 - ArrayList list = new ArrayList(); list.add(123); list.add("Ann"); list.add(new Students("Tom",18,90)); list.add(987); list.add(3,"AA"); System.out.println(list);//[123, Ann, Students{name='Tom', age=18, grade=90.0}, AA, 987]
- addAll(int index , Collection eles) - 从index位置开始将eles中的所有元素添加进来 - ArrayList list = new ArrayList(); list.add(123); list.add("Ann"); list.add(new Students("Tom",18,90)); list.add(987); ArrayList arrayList = new ArrayList(); arrayList.add(123); arrayList.add("Lisa"); list.addAll(arrayList); System.out.println(list);//[123, Ann, Students{name='Tom', age=18, grade=90.0}, 987, 123, Lisa]
注意使用的是add()还是addAll():
- add()方法中将添加的元素看成一个整体,无论eles中有多少个元素,添加后的元素个数就是+1
- addAll()方法中eles中有多少个元素,添加后就多多少个元素
- get(int index) - 获取指定index位置的元素 - System.out.println(list.get(1));//Ann
- indexOf(Object obj) - 返回obj在当前集合中首次出现的位置 - System.out.println(list.indexOf(123));//0- 若存在该元素,返回其第一次出现的位置
- 若不存在该元素,返回-1
 
- lastIndexOf(Object obj) - 返回obj在当前集合中最后一次出现的位置 - System.out.println(list.lastIndexOf(123));//4- 若存在该元素,返回其最后一次出现的位置
- 若不存在该元素,返回-1
 
- remove(int index) - 移除指定index位置元素,并返回此元素 - System.out.println(list.remove(1));//Ann System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 987, 123, Lisa]- 注意和Collection接口中的remove方法区分 
- set(int index , Object ele) - 设置指定index位置的元素为ele - System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 987, 123, Lisa] list.set(2,789); System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 789, 123, Lisa]
- subList(int fromIndex , int toIndex) - 返回从fromIndex到toIndex位置的子集合(左闭右开) - System.out.println(list);//[123, Students{name='Tom', age=18, grade=90.0}, 789, 123, Lisa] System.out.println(list.subList(1, 3));//[Students{name='Tom', age=18, grade=90.0}, 789]
总结
- 增:add(Object obj) 
- 删:remove(int index)、remove(Object obj) 
- 改:set(int index , Object obj) 
- 查:get(int index) 
- 插:add(int index , Object obj) 
- 长度:size() 
- 遍历 - ① Iterator迭代器方式 - ②增强for循环 - ③普通循环 
注:区分remove方法(形参)
- List接口中remove方法要求里面的形参是int类型
- Collection接口中remove方法要求里面的形参是对象
- 若list中元素为1,2,3;remove(2)表明移除位置为2的元素;若想要移除元素2,需要remove(new Integer(2))
 
  
  
  
 
