JAVA集合类汇总(List)(学习笔记二)

本文介绍了JAVA中的List接口及其常见的实现类ArrayList、LinkedList和Vector。ArrayList基于数组实现,适合频繁查找,增删较慢;LinkedList采用链表结构,增删快但占用更多空间;Vector是线程安全的ArrayList替代,但效率较低。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

publicinterface List<E> extends Collection<E>

        有序集合(也称为序列)。可以对每个集合内的元素由精确的控制(add.set.get.remove)可以通过其整数索引(集合的元素位置)访问元素,并搜索集合中元素的位置IndexOf(),lastIndexOf();

        

        与设置不同,列表通常允许重复的元素。更正式地说,列表通常允许对元素e1和e2进行配对,e1 = e2 (e2),如果它们允许null元素,它们通常允许多个null元素。有人可能希望实现一个禁止重复的列表,在用户试图插入时抛出运行时异常,但我们希望这种用法非常少见,这并不是不可思议的。

       列表接口对迭代器的契约、添加、删除、equals和hashCode方法进行了额外的规定,超出了集合接口中指定的规定。为了方便起见,这里还包括了其他继承方法的声明。

       List接口提供了四种方法来访问列表元素的位置(索引)。列表(如Java数组)是基于零的。注意,这些操作可能与某些实现(例如LinkedList类)的索引值成比例地执行。因此,如果调用者不知道实现,那么迭代列表中的元素通常更可取。

       List接口提供了一个特殊的迭代器,称为ListIterator,它允许元素插入和替换,以及迭代器接口提供的正常操作之外的双向访问。提供了一种方法来获取列表迭代器,它从列表中的指定位置开始。

       List接口提供了搜索指定对象的两种方法。从性能的角度来看,这些方法应该谨慎使用。在许多实现中,它们将执行昂贵的线性搜索。

       List接口提供了两种方法,可以有效地在列表的任意点插入和删除多个元素。

       注意:虽然列表可以将自己包含为元素,但建议非常谨慎:在这样的列表中,equals和hashCode方法不再被定义。

       一些列表实现对它们可能包含的元素有限制。例如,有些实现禁止空元素,有些实现对其元素的类型有限制。试图添加一个不合格的元素会抛出一个未检查的异常,通常是NullPointerException或ClassCastException。试图查询不合格元素的存在可能会抛出异常,或者它可能只是返回false;一些实现将展示前者的行为,而一些实现将展示后者。更一般的情况是,尝试对一个不合格的元素进行操作,其完成不会导致在列表中插入一个不合适的元素,可能会抛出异常,或者在实现的选项中可能会成功。在这个接口的规范中,这些异常被标记为“可选”。

        这个是JDK1.8API List的实现

修饰符和类型

方法和描述

boolean

add(E e) 将指定的元素追加到这个列表的末尾(可选操作)

void

add(int index, E element) 将指定的元素插入到这个列表中的指定位置(可选操作)

boolean

addAll(Collection<? extends E> c) 将指定集合中的所有元素追加到该列表的末尾,并按照指定的集合的迭代器(可选操作)返回它们。

boolean

addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到指定位置的这个列表(可选操作)

void

clear()从这个列表中删除所有元素(可选操作)

boolean

contains(Object o) 如果该列表包含指定元素,则返回true

boolean

containsAll(Collection<?> c) 如果此列表包含指定集合的所有元素,则返回true

boolean

equals(Object o) 将指定的对象与此列表进行比较。

E

get(int index) 返回列表中指定位置的元素。

int

hashCode()返回此列表的哈希代码值。

int

indexOf(Object o) 返回该列表中指定元素的第一次出现的索引,或者如果该列表不包含元素,则返回-1

boolean

isEmpty()如果该列表不包含元素,则返回true

Iterator<E>

iterator()以适当的顺序返回列表中元素的迭代器。

int

lastIndexOf(Object o) 返回该列表中指定元素的最后一次出现的索引,或者如果该列表不包含元素,则返回-1

ListIterator<E>

listIterator()

在这个列表中的元素上返回一个列表迭代器(按正确的顺序)。

ListIterator<E>

listIterator(int index) 从列表中指定的位置返回列表中元素的列表迭代器(按正确顺序)

E

remove(int index) 在这个列表中删除指定位置的元素(可选操作)

boolean

remove(Object o) 如果存在(可选操作),则从该列表中删除指定元素的第一次出现。

boolean

removeAll(Collection<?> c) 从这个列表中删除所有包含在指定集合中的元素(可选操作)

default void

replaceAll(UnaryOperator<E> operator)

将此列表中的每个元素替换为将运算符应用到该元素的结果。

boolean

retainAll(Collection<?> c) 仅保留指定集合中包含的元素(可选操作)

E

set(int index, E element) 用指定的元素(可选操作)替换该列表中指定位置的元素。

int

size()返回列表中元素的数量。

default void

sort(Comparator<? super E> c)

根据指定的Comparator.所引起的顺序对列表进行排序。

default Spliterator<E>

spliterator()在此列表中的元素之上创建一个Spliterator

List<E>

subList(int fromIndex, int toIndex)

返回该列表中指定的fromIndex(包含)和toIndex(独占)之间的部分的视图。

Object[]

toArray()返回包含该列表中所有元素的数组(从第一个元素到最后一个元素)

<T> T[]

toArray(T[] a)

返回包含该列表中所有元素的数组(从第一个元素到最后一个元素);返回数组的运行时类型是指定数组的运行时类型。

List 的抽象实现类 AbstractList :

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>

         AbstractList继承自 AbstractCollection 类,实现了List接口。整个类设计类似于AbstractCollection,实现了大多数方法,抽象了对于需要根据数据操作的方法。

        

List 的实现类:

public class ArrayList<E> extends AbstractList<E>implements        List<E>, RandomAccess, Cloneable,java.io.Serializable

 

ArrayList 特点:

       1、容量不固定,可以动态扩容

       2、有序,(基于数组的实现)可重复

       3、元素可以Null

       4、效率高。速度快,增删慢,

                    查找操作的时间复杂度是 O(1)

                    增删操作的时间复杂度是 O(n)

                    其他操作基本也都是 O(n)

       5、线程不安全,

       6、当容量不够时,ArrayList 是当前的容量 * 1.5

       7、占用空间少,相比LinkedList,不用占用额外的空间维护表结构 

        MAX_ARRAY_SIZE :数组最大的容量(2147483639)

  ArrayList 其实就是基于数组的实现。因此,增删改查操作就变得很容易理解了。

    get(index)直接获取数组的底 index 个元素

    set(index,object)直接修改数组的第 index 个元素的引用

    add(index,object)添加一个元素到index,(这个会牵扯到数组的扩容)

    

        扩容机制,假设我们现在有一个集合 list,里面正好含有10个元素,此时,我们调用 add(object)方法添加一个元素,

    

public boolean add(E var1) {
    //查看是数组长度是否够
    this.ensureCapacityInternal(this.size + 1);
    this.elementData[this.size++] = var1;
    return true;
}

private void ensureCapacityInternal(int var1) {
    //检查是否是默认长度为0的数组,如果是则长度设为10
    if(this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        var1 = Math.max(10, var1);
    }
    this.ensureExplicitCapacity(var1);
}

private void ensureExplicitCapacity(int var1) {
    ++this.modCount;
    //当前需要的长度大于数组长度,执行扩容操作
    if(var1 - this.elementData.length > 0) {
        this.grow(var1);
    }
}

private void grow(int var1) {
    int var2 = this.elementData.length;
    //var3 = var2*1.5;扩容1.5倍
    int var3 = var2 + (var2 >> 1);
    if(var3 - var1 < 0) {
        var3 = var1;
    }
    //新容量超出最大值
    if(var3 - 2147483639 > 0) {
        var3 = hugeCapacity(var1);
    }
    //重新创建了一个1.5倍容量的数组赋值给elementData
    this.elementData = Arrays.copyOf(this.elementData, var3);
}

        从上面我们可以看到,修改某个角标的值或者查找某个角标的值时,我们可以直接调用数组的操作,效率很高。但是添加和删除则是要操作整个数组的移动,效率稍低。这里我们也可以看到,其实 ArrayList 就是一个针对数组操作的封装类。


    

LinkedList

        刚刚我们看了 ArrayListArrayList 的增删操作效率相对较低。因此,Java 给我们设计了另外一种增删效率比较高的集合 LinkedList。LinkedList 继承自AbstractSequentialList。AbstractSequentialList 又继承自AbstractList,并且基于 iterator 实现了默认增删改查操作。再回过头来看 LinkedList,LinkedList 还实现了Deque(双向队列)接口,

        

LinkedList和ArrayList的区别:

    LinkedList和ArrayList的差别主要来自于ArrayList和LinkedList数据结构的不同:

1) 因为ArrayList是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。ArrayList获取数据的时间复杂度是O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。

2) 相对于ArrayList,LinkedList插入是更快的。因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)。

3) 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

4) LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。

    
public class Vector<E>

    extends AbstractList<E>

    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Vector


    继承了AbstractList 实现了,LIst,RrandomAccess,Cloneable,Serializable。和ArrysList 类似,但区别在于 Vector是同步类(Synchronized),效率相对会比较低。

    一般直接使用ArrayList,需要同步的话可以用Collections类的同步List静态方法来转换为同步List。

        Vector会在你不需要进行线程安全的时候,强制给你加锁,导致了额外开销,所以基本不用。

        Vector 在JDK1.0的时候出生的,而ArrayList是在JDK1.2的时候,才有的。Vector的默认扩容是当前容量*2(也就是两倍),ArryList前面讲过,是1.5倍。Vector 多了一种迭代器 Enumeration。

        Enumeration

public interface Enumeration<E> {
    /**
     * Tests if this enumeration contains more elements.
     *
     * @return  <code>true</code> if and only if this enumeration object
     *           contains at least one more element to provide;
     *          <code>false</code> otherwise.
     */
    boolean hasMoreElements();

    /**
     * Returns the next element of this enumeration if this enumeration
     * object has at least one more element to provide.
     *
     * @return     the next element of this enumeration.
     * @exception  NoSuchElementException  if no more elements exist.
     */
    E nextElement();
}

    这个应该是 线程安全的 iterator ?



public
class Stack<E> extends Vector<E>
Stack 继承自Vector ,也是一个线程安全的集合。

Stack 也是基于数组实现的。

Stack 实现的是栈结构集合

数据结构中,栈也是一种线性的数据结构,遵守 LIFO(后进先出)的操作顺序。

   public class Stack<E> extends Vector<E> {
            private static final long serialVersionUID = 1224463164541339165L;

            public Stack() {
            }

            //入栈,添加一个元素到数组的最后一个
            public E push(E var1) {
                this.addElement(var1);
                return var1;
            }
            //出栈,删除数组最后一个元素并返回
            public synchronized E pop() {
                int var2 = this.size();
                Object var1 = this.peek();
                this.removeElementAt(var2 - 1);
                return var1;
            }
            //获取最后一个元素,不删除
            public synchronized E peek() {
                int var1 = this.size();
                if(var1 == 0) {
                    throw new EmptyStackException();
                } else {
                    return this.elementAt(var1 - 1);
                }
            }

            public boolean empty() {
                return this.size() == 0;
            }
            获取栈中的 位置。
            public synchronized int search(Object var1) {
                int var2 = this.lastIndexOf(var1);
                return var2 >= 0?this.size() - var2:-1;
            }
        }
     整个类的实现非常简单,就是继承 Vector,然后添加了 peek、pop、push、search 等方法,然后然添加删除都在最末尾的元素做操作即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值