JDK8系列:刨根问底 之 List集合

对于数组我们应该很熟悉,一个数组在内存中总是一块连续的存储空间,数组的创建使用new关键字,数组是引用类型的数据,一旦第一个元素的位置确定,那么后面的元素位置也就确定了,数组有一个最大的局限就是数组一旦创建,他的长度就是固定的,不可以进行更改,如果数组空间不够大,唯一的方法就是再创建一个大的数组,把原来的数组元素拷贝过去

为了使程序鞥狗方便的存储和操作数量不固定的数据,java加入了集合个概念,和数组最大的区别也就是长度可以改变,是一种动态的调整

在java中一共有三种集合分别是List,Set,Map,三种集合有着各自的特点:

List(列表):集合中的每一个位置是按照索引位置放的,像一个柜子,一层一层的,可以有重复的元素,当我们想要取数据的时候,直接找对应的柜子的层号就可以找到,就是可以根据索引找到元素,是和数组最像的集合,

Set(集):集合中的每一个元素都是不按顺序进行排列,这也决定了Set集合中没有重复的元素,像篮子里的鸡蛋,无序不重复。

Map(映射):集合中的每一个元素都是按照键值对的方式存储,一个键对应一个值,键不可以重复,值可以重复,我们可以根据键找到值,也是无序的集合。

接下来我们看看各个集合类继承和实现类

 

关于 JDK8系列:Collection接口 AND AbstractCollection抽象类

1、List 接口

public interface List<E> extends Collection<E> {
    ......
}

1.1、查询操作

int size();
boolean isEmpty();
boolean contains(Object o);

Iterator<E> iterator();

Object[] toArray();
<T> T[] toArray(T[] a);

1.2、修改操作

boolean add(E e);
boolean remove(Object o);

1.3、批量操作

boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);

default void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final ListIterator<E> li = this.listIterator();
    while (li.hasNext()) {
        li.set(operator.apply(li.next()));
    }
}

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

void clear();

1.4、比较和哈希

boolean equals(Object o);
int hashCode();

1.5、位置访问操作

E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);

1.6、搜索操作

int indexOf(Object o);
int lastIndexOf(Object o);

1.7、List Iterators

ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);

default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.ORDERED);
}

 

2、AbstractList  抽象类

2.1、简介

此类提供了List接口的骨架实现(也称为:抽象接口),以最大限度地减少实现由“随机访问”数据存储(如数组) * 所支持的接口所需的工作量. *

对于顺序访问数据(如链表),应该使用AbstractSequentialList类.

为了实现一个不可修改的list,程序员上仅仅需要扩展此类,并提供一个get()方法和size()方法的实现即可.

为了实现一个可以修改的类,程序员上必须额外覆盖set(int,Object),set(int,E)方法. * 如果list的大小是可变的,则程序员上应该额外覆盖add()方法,remove()方法.

 

2.2、成员变量  及 内部类简介

成员变量

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    // modCount记录了list的结构修改次数
    // modCount域被iterator迭代器和ListIterator迭代器使用
    // 如果modCount值和预期不一样,则抛出并发异常ConcurrentModificationException
    // 如果一个实现的迭代器不提供快速实现的功能,则可以不使用这一域 
    protected transient int modCount = 0;
    ......
}

 Itr  

private class Itr implements Iterator<E> {
    // 下一个调用返回的元素的索引
    int cursor = 0;

    // 最近一次调用next或previous返回的元素的索引。如果通过调用remove删除此元素,则重置为-1
    int lastRet = -1;

    // 迭代器认为支持列表应该具有的modCount值。如果违反此期望,则迭代器已检测到并发修改
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size();
    }

    public E next() {
        ......
    }

    public void remove() {
        ......
    }
}    

ListItr

private class ListItr extends Itr implements ListIterator<E> {
    
    ListItr(int index) {cursor = index;}
    
    public E previous() { ......}

    public int nextIndex() { return cursor; }

    public int previousIndex() { return cursor-1; }

    public void set(E e) { ...... } 
    
    public void add(E e) { ...... }
}

SubList

class SubList<E> extends AbstractList<E> {
    private final AbstractList<E> l;
    private final int offset;
    private int size;

    SubList(AbstractList<E> list, int fromIndex, int toIndex) { ...... }

    public E set(int index, E element) { ...... }

    public E get(int index) { ...... }

    public int size() { ...... }

    public void add(int index, E element) { ...... }

    public E remove(int index) { ...... }

    protected void removeRange(int fromIndex, int toIndex) { ...... }

    public boolean addAll(Collection<? extends E> c) { return addAll(size, c); }

    public boolean addAll(int index, Collection<? extends E> c) { ...... }

    public Iterator<E> iterator() { ...... }

    public ListIterator<E> listIterator(final int index) { ...... }

    public List<E> subList(int fromIndex, int toIndex) { ...... }

    private void rangeCheck(int index) { ...... }
    
    private String outOfBoundsMsg(int index) { ...... }

    private void checkForComodification() { ...... }
}

RandomAccessSubList

class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
    RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
        super(list, fromIndex, toIndex);
    }

    public List<E> subList(int fromIndex, int toIndex) {
        return new RandomAccessSubList<>(this, fromIndex, toIndex);
    }
}

 

2.3、构造方法

唯一构造器.(通常由子类构造函数隐式调用,因为protected修饰,且无参数,所以可以被子类使用)

protected AbstractList() {}

 

2.4、添加元素

add(E e)

// 1.这一方法如果没有被覆写,则直接抛出异常.因为add(size(),ze)这个add方法抛异常
// 2.这一方法调用了size方法
public boolean add(E e) {
    add(size(), e);
    return true;
}

add(int index, E element)  

// 默认抛出异常,需要子类重写
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

 set(int index, E element) 

// 默认抛出异常,需要子类重写
public E set(int index, E element) {
    throw new UnsupportedOperationException();
}

addAll(int index, Collection<? extends E> c) 

// 将集合c中的元素添加到list中,从list的下表index开始放置
public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);
    boolean modified = false;
    for (E e : c) {
        add(index++, e);
        modified = true;
    }
    return modified;
}

 

2.5、获取元素

get(int index)

abstract public E get(int index);

 

2.6、删除元素

remove(int index)

// 默认抛出异常,需要子类重写
public E remove(int index) {
    throw new UnsupportedOperationException();
}

 removeRange(int fromIndex, int toIndex)

// 删除list中从 fromIndex到toIndex的元素
protected void removeRange(int fromIndex, int toIndex) {
    ListIterator<E> it = listIterator(fromIndex);  //返回从fromIndex开始的子集
    for (int i=0, n=toIndex-fromIndex; i<n; i++) {
        it.next();
        it.remove();
    }
}

 

2.7、搜索操作

indexOf(Object o) 

// 返回 o在List中第一次出现的位置
public int indexOf(Object o) {
    ListIterator<E> it = listIterator();  //list迭代器
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
        return it.previousIndex();
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return it.previousIndex();
    }
    return -1;
}

lastIndexOf(Object o)  

// 返回o在List中最后一个出现的位置
public int lastIndexOf(Object o) {
    ListIterator<E> it = listIterator(size());
    if (o==null) {
        while (it.hasPrevious())
            if (it.previous()==null)
                return it.nextIndex();
    } else {
        while (it.hasPrevious())
            if (o.equals(it.previous()))
                return it.nextIndex();
    }
    return -1;
}

 

2.8、其他操作

rangeCheckForAdd(int index) 

// 检查index是否在list的范围内
private void rangeCheckForAdd(int index) {
    if (index < 0 || index > size())
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

clear()

public void clear() {
    removeRange(0, size());
}

iterator() 

public Iterator<E> iterator() {
    return new Itr();
}

listIterator() 

public ListIterator<E> listIterator() {
    return listIterator(0);
}

listIterator(final int index) 

public ListIterator<E> listIterator(final int index) {
    rangeCheckForAdd(index);

    return new ListItr(index);
}

subList(int fromIndex, int toIndex) 

public List<E> subList(int fromIndex, int toIndex) {
    return (this instanceof RandomAccess ?
                            new RandomAccessSubList<>(this, fromIndex, toIndex) :
                            new SubList<>(this, fromIndex, toIndex));
}

equals(Object o) 

public boolean equals(Object o) {
    if (o == this)  // o就是list本身
        return true;
    if (!(o instanceof List))   //o不是List类型
        return false;

    ListIterator<E> e1 = listIterator();
    ListIterator<?> e2 = ((List<?>) o).listIterator();
    // 一个一个元素比较
    while (e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        if (!(o1==null ? o2==null : o1.equals(o2)))
            return false;
    }
    return !(e1.hasNext() || e2.hasNext());
}

hashCode() 

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

outOfBoundsMsg(int index) 

private String outOfBoundsMsg(int index) {
    return "Index: "+index+", Size: "+size();
}

 

3、常用的 List 的实现类

JDK8系列:List集合 之 ArrayList 源码分析

JDK8系列:List集合 之 LinkedList 源码分析

 

4、对比分析

分析得出下面结论:

(1)ArrayList 本质上是一个可改变大小的数组.当元素加入时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问.元素顺序存储 ,随机访问很快,删除非头尾元素慢,新增元素慢而且费资源 ,较适用于无频繁增删的情况 ,比数组效率低,如果不是需要可变数组,可考虑使用数组 ,非线程安全.

(2)LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList. 适用于 :没有大规模的随机读取,有大量的增加/删除操作.随机访问很慢,增删操作很快,不耗费多余资源 ,允许null元素,非线程安全.

(3)Vector (类似于ArrayList)但其是同步的,开销就比ArrayList要大。如果你的程序本身是线程安全的,那么使用ArrayList是更好的选择。 Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值