list接口:是connection接口的子接口,也是最常用的接口。此接口对connection接口进行了大量的扩充。里面的内容是允许重复允许为空并且有序(插入顺序有序)。
1、ArrayList
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
1.1ArrayList特点
ArrayList实现了List, RandomAccess, Cloneable, java.io.Serializable接口,具有以下特点:
1、List:存放单值,里面的内容允许重复允许为空并且有序(插入的顺序)
2、Cloneable:集合可以使用clone方法
3、Serializable:可以序列化
4、RandomAccess:ArrayList可以被随机访问
5、Iterator:ArrayList可以使用迭代器遍历ListIterator:是Iterator接口的子接口,可以进行双向输出
1.2ArrayList源码中的一些方法介绍
增加方法:
add(int index,type element); //向指定下标添加元素
add(type element);//在List末尾添加元素
//批量添加
addAll(Collection c)//在集合末尾添加集合类元素 两个集合的并集
addAll(int index, Collection c)//在集合指定位置添加集合类元素
删除方法:
remove(Object o)//删除元素
remove(int index)//删除下标对应的元素
removeAll(Collection c)//在集合删除集合类元素
//list.removeAll(list1) 从list中移除(list和list1的公共元素)
retainAll(Collection c)//求交集,移除非交集元素
//list.retainAll(list1) list保留和list1的公共元素,其他元素删除
1.3两个ArrayList交集/不重复并集/差集
import java.util.ArrayList;
public class ArrayList2 {
public static void main(String[] args){
ArrayList list = new ArrayList();
ArrayList list1= new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list1.add(1);
list1.add(2);
list1.add(5);
list1.add(6);
list1.add(7);
/**
* list.retainAll(list1) list保留和list1的公共元素,其他元素删除
* list.retainAll(list1);//1 2 3 4 1 2 5 6 7
* 遍历结果:交集
* 1 2
*/
/**
* list.removeAll(list1) 从list中移除(list和list1的公共元素)
* list.removeAll(list1);//1 2 3 4 1 2 5 6 7
* 遍历结果:差集
* 3 4
*/
list.removeAll(list1);//list 1 2 3 4 list1 1 2 5 6 7 list---->3 4
list1.addAll(2,list);//list1 1 2 5 6 7 list 3 4
System.out.println("不重复并集:");
for (int i = 0; i < list1.size(); i++) {
System.out.print(list1.get(i) + " ");
}
}
}
1.4实现MyArrayList
package JiHe.OneArrayList;
import java.util.*;
public class MyArrayList<T> {
private Object[] elementData;//泛型数组 ArrayList的底层数据结构
private int size;//数组中存放的元素个数(不是容量)
private int DEFULT_SIZE =10;//ArrayList默认大小
private static final Object[] EMPTY_ELEMENTDATA = {};//定义一个空数组,
/**
* 无参构造函数:
* - 创建一个 空的 ArrayList,此时其内数组elementData = {}, 长度为 0
* - 当元素第一次被加入时,扩容至默认容量 10
*/
public MyArrayList() {
elementData = EMPTY_ELEMENTDATA;
}
private class Itr implements Iterator<T>{ //具体迭代器角色
public int cur; //当前元素下标
@Override
public boolean hasNext() { //判断是否遍历结束,当cursor不等size时表示有下个元素
return cur != size;
}
@Override
public T next() { //获取当前元素的方法,并且移动到下一个元素的位置
return (T)elementData[cur++];
}
@Override
public void remove() { //移除当前对象的方法
MyArrayList.this.remove(cur);
}
}
private class ListItr extends Itr implements ListIterator<T>{
ListItr(int index) {
super();
cur = index;
}
@Override
public boolean hasPrevious() {
return false;
}
@Override
public T previous() {
return null;
}
@Override
public int nextIndex() {
return 0;
}
@Override
public int previousIndex() {
return 0;
}
@Override
public void set(T t) {
}
@Override
public void add(T t) {
}
}
public Iterator<T> iterator() {
return new Itr();
}
public ListIterator<T> listIterator() {
return new ListItr(0);
}
public int getSize() {
return size;
}
//扩容方法
private void grow(int size){
//如果数组原来是空数组,扩容从0到默认大小10,否则扩容至原来大小的1.5倍
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if(newCapacity - size < 0){
newCapacity = DEFULT_SIZE;
}
elementData =Arrays.copyOf(elementData,newCapacity);
}
//检查下标越界
private void rangeCheck(int index){
if(index >= size || index < 0){
throw new IndexOutOfBoundsException();
}
}
//检查ArrayList容量,插入元素是否需要进行扩容操作
private void ensureCapacity(int size){
if(size>elementData.length){
grow(size);
}
}
//增删改查方法
//增加操作
public void add(T value){//尾部添加
//判断ArrayList的容量大小
ensureCapacity(size+1);
elementData[size++] = value;
}
public void add(int index,T value){//向指定下标添加元素(数据的移动) ArrayList不适合随机插入
//判断下标是否越界
rangeCheck(index);
ensureCapacity(size+1);
System.arraycopy(elementData,index,elementData,index+1,size -index);
//原数组 原数组起始位置 目标数组 目标数组起始位置 移动元素个数
elementData[index] = value;
size++;
}
//删除操作
public void remove(int index){ //删除某个下标元素
rangeCheck(index);
System.arraycopy(elementData,index+1,elementData,index,size - index-1);
elementData[--size] = null;
// elementData[size-1] =null;//GC
// size--;
}
public boolean remove1(Object value){//删除某个元素
//遍历数组,如果不存在该元素,不发生改变,如果含有该元素,将该元素删除,数据移动
if(value == null){ //ArrayList允许空值
for(int i = size;i>=0;i--){ //int i =0;i< size;i++这种情况下 如果数组中有重复值只删除第一个值
if(elementData[i] ==value){
// System.arraycopy(elementData,i+1,elementData,i,size -i-1);
// elementData[--size] = null;
fastRemove(i);
}
return true;
}
}else{
for(int i = size;i>=0;i--){
if(value.equals(elementData[i])){
fastRemove(i);
}
}
return true;
}
return false;
}
private void fastRemove(int index){
System.arraycopy(elementData,index+1,elementData,index,size -index-1);
elementData[--size] = null;
}
//查
//获取某位置的元素
public T get(int index){
//判断下标是否越界
rangeCheck(index);
return (T)elementData[index];
}
//查找数组中是否有该元素
public boolean contains(Object value){
// 存在问题,如果数组中有空元素,如size=3,elementData.length = 4,存在空指针异常
// for(int i = 0;i<size;i++){
// if(elementData[i].equals(value)) {
// return true;
// }
// }
// return false;
return indexOf(value) >=0; //根据元素下标来判断
}
public int indexOf(Object o) { //找到元素所对应的下标
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
//改
//修改某位置的元素
public void set(int index,T value){
rangeCheck(index);
elementData[index] = value;
}
//查找是否包含元素
}
2、LinkedList
public class LinkedList
extends AbstractSequentialList
implements List, Deque, Cloneable, java.io.Serializable
2.1 LinkedLis特点
LinkedList:既是list接口下的集合,也是queue接口下的集合
LinkedList 是一个继承于AbstractSequentialList的双向链表。底层是使用了链表数据结构实现的.它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。存放单值,里面的内容允许重复允许为空并且有序(插入的顺序)
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,LinkedList支持序列化,能通过序列化去传输。LinkedList可以被随机访问
Iterator:LinkedList可以使用迭代器遍历ListIterator:是Iterator接口的子接口,可以进行双向输出;private class ListItr implements ListIteratorprivate class DescendingIterator implements Iterator,进行从前往后遍历
2.2MyLinkedList实现
package JiHe.OneLinkedList;
import java.util.Iterator;
public class MyLinkedList<T> {
private Node<T> first;//头指针
private Node<T> last;//尾指针
private int size;//数据数量
public MyLinkedList() {
}
public void add(T item){//尾插法
Node<T> l = last;
Node<T> newNode = new Node(item,l,null);
if(l == null){
first = newNode;
}else{
l.next = newNode;//增加判断条件,如果last为空会出现空指针异常
}
last = newNode;
size++;
}
private Node node(int index){//获取index位置的结点
if (index < (size >> 1)) {//如果index是链表的前半部分,从前往后遍历
Node<T> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//如果index是链表的后半部分,从后往前遍历
Node<T> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
//检查index合法性
private void checkIndex(int index){
if(index >size || index <0){
throw new IndexOutOfBoundsException();
}
}
public void add(int index, T item){//在指定索引位置之前插入元素e
//判断index是否合法,如果s为空,说明超过了size的值
//如果index=size,即尾插
checkIndex(index);
if(index == size){
add(item);
return;
}
Node<T> s = node(index);
Node<T> pre = s.prev ;
Node<T> newNode = new Node(item,pre,s);
s.prev = newNode;
if(pre == null){
first = newNode;
}else{
pre.next = newNode;
}
size++;
}
public void remove(int index){
checkIndex(index);
Node<T> s = node(index);
T element = s.item;
Node<T> prev = s.prev;
Node<T> next = s.next;
//四种情况(分步思考)
//只有s这个结点(prev ==null, next == null)
//s是头结点(prev ==null,next != null)
//s是尾巴结点(prev != null,next == null)
//s是链表中间某个结点(prev != null , next != null)
if(prev == null){
first = next;
}else{
prev.next = next;
s.prev = null;
}
if(next == null){
last = prev;
}else{
next.prev = prev;
s.next = null;
}
element = null;
size--;
}
public void set(int index,T value){
checkIndex(index);
Node<T> node = node(index);
node.item = value;
}
public T get(int index){
checkIndex(index);
Node<T> node = node(index);
return node.item;
}
public int size(){
return size;
}
private static class Node<T>{
T item;
Node<T> prev;
Node<T> next;
public Node(T item, Node<T> prev, Node<T> next) {
this.item = item;
this.prev = prev;
this.next = next;
}
}
//迭代器实现
private class MyIterator implements Iterator<T> {
public int curIndex;//当前结点下标
@Override
public boolean hasNext() {//判断是否遍历结束,判断当前结点下标和size关系
return curIndex < size;
}
@Override
public T next() {//获取当前元素的方法
if(curIndex == 0){ // 当前结点是头结点
curIndex++;
return first.item;
}else{
curIndex++;
first = first.next;
return first.item;
}
}
@Override
public void remove() {//移除当前对象的方法
MyLinkedList.this.remove(curIndex);
}
}
public Iterator<T> iterator() {
return new MyIterator();
}
}
3.Vector
public class Vector
extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
可以发现Vector和ArrayList继承与实现相同,故Vector的特点和ArrayList相似
4.List接口下的集合比较
4.1LinkedList与ArrayList的区别
LinkedList与ArrayList在性能上各有优缺点,都有各自适用的地方,总结如下:
- 底层结构:ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。LinkedList不支持高效的随机元素访问。
- ArrayList的空间浪费主要体现在在l数组的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间(前驱,后继),就存储密度来说,ArrayList是优于LinkedList的。
- 使用场景:当操作是在一列数据的后面添加删除数据,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能,当你的操作是在一列数据的随机添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了,LinkedList更适合随机添加删除方法比较频繁的操作,不需要进行数据的移动。
4.2Vector和ArrayList的区别
主要体现在 源码上:
- 底层数据结构:Vector和ArrayList底层数据结构都是数组;
- 构造函数:ArrayList初始数组大小为空,添加第一个元素时数组容量变为10; Vector初始数组大小为10;
- grow()方法:ArrayList中添加第一个元素时数组容量0变为10,之后成1.5倍扩容; Vector中如果capacityIncrement大于0,容量增加capacityIncrement个,如果capacityIncrement小于0,即2倍扩容(默认情况下Vector二倍扩容)。扩容方式vector更合理。
- 线程安全:Vector所有方法都添加了synchronized锁,所以Vector是线程安全的集合,但是加锁操作非常耗时,效率低;而ArrayList是线程不安全的集合。