list接口:
collection的子接口:
一个 List 是一个元素有序的、可以重复、可以为 null 的集合(有时候我们也叫它“序列”)。
Java 集合框架中最常使用的几种 List 实现类是 ArrayList,LinkedList 和 Vector。在各种 List 中,最好的做法是以 ArrayList 作为默认选择。 当插入、删除频繁时,使用 LinkedList,Vector 总是比 ArrayList 慢,所以要尽量避免使用它,具体实现后续文章介绍。
为什么 List 中的元素 “有序”、“可以重复”呢?
首先,List 的数据结构就是一个序列,存储内容时直接在内存中开辟一块连续的空间,然后将空间地址与索引对应。
List 接口的实现类在实现插入元素时,都会根据索引进行排列。
由于 List 的元素在存储时互不干扰,没有什么依赖关系,自然可以重复(这点与 Set 有很大区别)。
List 接口定义的方法
List 中除了继承 Collection 的一些方法,还提供以下操作:
List集合的特有功能:
添加功能:
void add(int index, Object element)在列表的指定位置插入指定元素
删除功能:
Object remove(int index)移除列表中指定位置的元素,返回被删除的元素
获取功能:
ListIterator listIterator():列表迭代器:List集合的专有遍历方式
Object get(int index)返回列表中指定位置的元素。
替换
set(int index,Object element)用指定元素替换列表中指定位置的元素
list的遍历:
1.使用普通for的方法去遍历list集合,使用size()和get()相结合
2.通过toArray()转换成数组在使用for循环遍历
3.集合遍历:
List集合的列表迭代器
ListIterator listIterator()
列表迭代器接口中有以下几个方法:
boolean hasNext():判断是否有下一个可以迭代的元素(正向遍历)
Object next():如果有可以遍历的元素,就获取这个元素
boolean hasPrevious():判断是否有上一个可以迭代的元素(逆向遍历)
Object previous():如果有上一个可以迭代的元素,就获取上一个元素
注意:
要使用逆向遍历,前提必须有正向遍历存在,直接使用逆向遍历,没有意义
public class ListDemo3 {
public static void main(String[] args) {
//创建集合对象
List list = new ArrayList() ;
//给集合中添加元素
list.add("hello") ;
list.add("world") ;
list.add("java") ;
//获取列表迭代器
ListIterator it = list.listIterator() ;
while(it.hasNext()){
String s = (String)it.next();
System.out.println(s);
}
System.out.println("-----------------------");
//boolean hasPrevious():判断是否有上一个可以迭代的元素(逆向遍历)
//Object previous():如果有上一个可以迭代的元素,就获取上一个元素
while(it.hasPrevious()){
String s = (String)it.previous() ;
System.out.println(s);
}
}
}
list的子实现类ArrayList:
ArrayList概述:
ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。由于ArrayList是List集合的自实现类,它元素可以重复,并且存储和取出一致。
每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步
ArrayList的实现:
对于ArrayList而言,它实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作。下面我们来分析ArrayList的源代码:
1) 底层使用数组实现:
private transient Object[] elementData;
所以满足数组结构的特点:查询快,增删慢从线程安全问题来看:线程不安全的,不同步,执行效率高。2) 构造方法:
ArrayList提供了三种方式的构造器,可以构造一个默认初始容量为10的空列表、构造一个指定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。
public ArrayList() {
this(10);
}
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
3)Arraylist常用方法:
E get(int index);
返回下标为index的元素;
E set(int index, E element);
改变下标为index的元素的值
void add(int index, E element);
在下标为index的地方插入元素element,该操作涉及数组移动;
E remove(int index);
移除下标为index的元素,该操作涉及数组移动;
int indexOf(Object o);
返回元素o的最小下标,通过调用o的equals方法与集合中的元素进行比较;
int lastIndexOf(Object o);
返回元素o的最大下标,通过调用o的equals方法与集合中的元素进行比较;
ListIterator listIterator();
返回listIterator迭代器,该迭代器支持向前操作;
ListIterator listIterator(int index);
返回listIterator迭代器,从特定的位置开始,该迭代器支持向前操作;
List subList(int fromIndex, int toIndex);
返回下标在fromIndex和toIndex之间的元素集import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < 10; i++){
list.add(i);
}
System.out.println(list);
//addAll方法
list.addAll(5, Arrays.asList(666,666, 6));
System.out.println(list);
//get方法
System.out.println(list.get(5));
//set方法
list.set(5, 55);
System.out.println(list.get(5));
//add方法
list.add(0, 555);
System.out.println(list);
//remove方法
list.remove(0);
System.out.println(list);
//indexof方法
System.out.println(list.indexOf(6));
//lastIndexOf方法
System.out.println(list.lastIndexOf(6));
//listIterator方法
ListIterator<Integer> listIterator = list.listIterator();
System.out.println(listIterator.hasPrevious());
//listIterator(index)方法
ListIterator<Integer> iListIterator = list.listIterator(5);
System.out.println(iListIterator.previous());
//subList方法
System.out.println(list.subList(5, 7));
}
}
4)Arrayliat遍历:
一般工作中用的比较多的是遍历操作,ArrayList支持三种方式
for循环下标遍历;
迭代器(Iterator和ListIterator);
foreach语句。
5) 调整数组容量:
从上面介绍的向ArrayList中存储元素的代码中,我们看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
从上述代码中可以看出,数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。
ArrayList还给我们提供了将底层数组的容量调整为当前列表保存的实际元素的大小的功能。它可以通过trimToSize方法来实现。代码如下:
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
6) Fail-Fast机制:
ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。具体介绍请参考我之前的文章深入Java集合学习系列:HashMap的实现原理 中的Fail-Fast机制.
List的子实现类Vector:
Vector:
底层数据结构是数组的形式,查询快,增删慢
从线程角度看:线程安全的类,同步,执行效率低
特有功能:
public void addElement(E obj)------->相当于:add(Object e)
public Enumeration<E> elements()----->相当于:Iterator iterator() ;
Enumeration<E>接口:向量的组件枚举有两个方法
boolean hasMoreElements():------>相当于:hasNext()
Object nextElement():----------->相当于:next();
源码:
synchronized:同步锁(多线程中讲):它就可以保证线程安全!
public synchronized void addElement(E obj) {//由同步代码块演变过来的同步方法
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
public class VectorDemo {
public static void main(String[] args) {
//创建一个Vector集合对象
Vector v = new Vector() ;
//添加元素
//public void addElement(E obj)
v.addElement("hello");
v.addElement("hello");
v.addElement("world");
v.addElement("Java");
//public Enumeration<E> elements()----->相当于:Iterator iterator() ;
Enumeration en = v.elements() ;
//遍历元素
/**
* boolean hasMoreElements():------>相当于:hasNext()
Object nextElement():----------->相当于:next();
*/
while(en.hasMoreElements()){
//获取元素
String s = (String)en.nextElement() ;
System.out.println(s);
}
}
}
List的子实现类Linkedlist:
LinkedList:
底层数据结构是链接列表,特点:查询慢,增删快
从线程角度看:线程不安全的一个类,不同步,执行效率高
特有功能:
添加功能:
public void addFirst(E e)将指定元素插入此列表的开头。
public void addLast(E e)将指定元素添加到此列表的结尾。
获取功能:
public Object getFirst()返回此列表的第一个元素
public Object getLast()返回此列表的最后一个元素。
删除功能:
public Object removeFirst()移除并返回此列表的第一个元素。
public Object removeLast()移除并返回此列表的最后一个元素。
public class LinkedListDemo {
public static void main(String[] args) {
//创建LinkedList集合
LinkedList link = new LinkedList() ;
//添加元素
link.addFirst("hello") ;
link.addFirst("world") ;
link.addFirst("Java") ;
//public void addFirst(E e)将指定元素插入此列表的开头
/*link.addFirst("android") ;
link.addLast("JavaWeb") ;*/
/**
* public Object getFirst()返回此列表的第一个元素
public Object getLast()返回此列表的最后一个元素。
*/
/*
Object obj = link.getFirst() ;
System.out.println(obj);
Object obj2 = link.getLast() ;
System.out.println(obj2);*/
/**
* public Object removeFirst()移除并返回此列表的第一个元素。
public Object removeLast()移除并返回此列表的最后一个元素。
*/
/*System.out.println("removeFirst:"+link.removeFirst());
System.out.println("removeLast:"+link.removeLast());*/
//输出集合
System.out.println("link:"+link);
}
}