List接口包含List接口及List接口的所有实现类,List集合中的元素允许重复。

List接口

List接口继承了Collection接口,包含Collection接口的所有方法,还定义了两个非常重要的方法

get(int index): 获得指定索引位置的元素

set(int index, Object obj):将集合中指定索引位置的对象修改为指定对象

List接口的实现类

List接口的实现类有ArrayList和LinkedList

  • ArrayList实现了可变的数组(底层是数组实现),允许保存所有元素,可以根据索引位置进行快速的随机访问;缺点是向指定索引位置插入对象或删除对象的速度较慢
  • LinkedList采用链表结构保存对象(底层是链表实现),优点是便于向集合中插入和删除对象

实例化集合

List<E> list = new ArrayList<>();

List<E> list2 = new LinkedList<>();

E是合法的java类型

ArrayList

ArrayList是Java集合框架中使用最多的一个类,是一个数组队列,线程不安全集合。

它继承于AbstractList,实现了List, RandomAccess, Cloneable, Serializable接口。

  1. ArrayList实现List,得到了List集合框架基础功能;
  2. ArrayList实现RandomAccess,获得了快速随机访问存储元素的功能,RandomAccess是一个标记接口,没有任何方法;
  3. ArrayList实现Cloneable,得到了clone()方法,可以实现克隆功能;
  4. ArrayList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。

它具有如下特点:

  • 容量不固定,随着容量的增加而动态扩容(阈值基本不会达到)
  • 有序集合(插入的顺序==输出的顺序)
  • 插入的元素可以为null
  • 增删改查效率更高(相对于LinkedList来说)
  • 线程不安全

ArrayList底层实现

ArrayList底层是使用数组来实现的

源码解析:

// 重要的几个变量

private static final int DEFAULT_CAPACITY = 10;

// 用数组保存arraylist的对象

transient Object[] elementData;

private int size;

//ArrayList初始化,实际是初始化一个存放object的数组

public ArrayList() {

     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

// grow方法,扩充ArrayList,通过Arrays.copyOf()方法返回一个扩充完毕的新数组,往ArrayList最后面添加一个元素

    private void grow(int minCapacity) {

        // overflow-conscious code

        int oldCapacity = elementData.length;

        int newCapacity = oldCapacity + (oldCapacity >> 1);

        if (newCapacity - minCapacity < 0)

            newCapacity = minCapacity;

        if (newCapacity - MAX_ARRAY_SIZE > 0)

            newCapacity = hugeCapacity(minCapacity);

        // minCapacity is usually close to size, so this is a win:

        elementData = Arrays.copyOf(elementData, newCapacity);

    }

// 指定index添加元素,通过System.arraycopy给数组添加值   

    public void add(int index, E element) {

        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!

        System.arraycopy(elementData, index, elementData, index + 1,size - index);

        elementData[index] = element;

        size++;

    }

  

Arrays.copyOf和System.arraycopy

  1. System.arraycopy()需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置
  2. Arrays.copyOf()是系统自动在内部新建一个数组,调用System.arraycopy()将original内容复制到copy中去,并且长度为newLength。返回copy; 即将原数组拷贝到一个长度为newLength的新数组中,并返回该数组。

Array.copyOf()可以看作是受限的System.arraycopy(),它主要是用来将原数组全部拷贝到一个新长度的数组,适用于数组扩容。

LinkedList

LinkedList是一个双向链表,每一个节点都拥有指向前后节点的引用。相比于ArrayList来说,LinkedList的随机访问效率更低。

它继承AbstractSequentialList,实现了List, Deque, Cloneable, Serializable接口。

  1. LinkedList实现List,得到了List集合框架基础功能;
  2. LinkedList实现Deque,Deque 是一个双向队列,也就是既可以先入先出,又可以先入后出,说简单些就是既可以在头部添加元素,也可以在尾部添加元素;
  3. LinkedList实现Cloneable,得到了clone()方法,可以实现克隆功能;
  4. LinkedList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。

LinkedList的底层实现

LinkedList的底层实现是双向链表,因此它有个内部类Node代表每个节点,即存储的每个元素

 private static class Node<E> {

        E item;

        Node<E> next;

        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {

            this.item = element;

            this.next = next;

            this.prev = prev;

        }

    }

  

我们来看LinkedList是如何进行删除和添加元素的:

// 增加LinkedList头元素

    private void linkFirst(E e) {

        final Node<E> f = first;

        final Node<E> newNode = new Node<>(null, e, f);

        first = newNode;

        if (f == null)

            last = newNode;

        else

            f.prev = newNode;

        size++;

        modCount++;

    }

    // 增加LinkedList尾元素

    void linkLast(E e) {

        final Node<E> l = last;

        final Node<E> newNode = new Node<>(l, e, null);

        last = newNode;

        if (l == null)

            first = newNode;

        else

            l.next = newNode;

        size++;

        modCount++;

    }

    // 在index处增加元素

    public void add(int index, E element) {

        checkPositionIndex(index);

        if (index == size)

            linkLast(element);

        else

            linkBefore(element, node(index));

    }

    // node(index)是获取index处的元素

    // linkBefore是在元素前增加一个元素

    // 删除index处的元素

    // 先检查元素是否存在,然后解链

    public E remove(int index) {

        checkElementIndex(index);

        return unlink(node(index));

    }

  

总结,以上就是List两个重要的实现类ArrayList和LinkedList的实现和常用的方法的源码介绍,后续我们根据实际需要处理来选择不同的实现类来帮助我们处理问题。

java集合类-List接口的更多相关文章

  1. Java集合类根接口:Collection 和 Map

    前言 在前文中我们了解了几种常见的数据结构,这些数据结构有着各自的应用场景,并且被广泛的应用于编程语言中,其中,Java中的集合类就是基于这些数据结构为基础. Java的集合类是一些非常实用的工具类, ...

  2. java集合类-Set接口

    Set集合 Set集合中的对象不按特定的方式排序,只是简单的把对象放入集合中,但是不能包含重复对象. Set集合由Set接口和Set接口的实现类组成,Set接口继承与于Collection接口 Set ...

  3. Java集合类源码解析:AbstractMap

    目录 引言 源码解析 抽象函数entrySet() 两个集合视图 操作方法 两个子类 参考: 引言 今天学习一个Java集合的一个抽象类 AbstractMap ,AbstractMap 是Map接口 ...

  4. Java集合类框架的基本接口有哪些?

    总共有两大接口:Collection 和Map ,一个元素集合,一个是键值对集合: 其中List和Set接口继承了Collection接口,一个是有序元素集合,一个是无序元素集合: 而ArrayLis ...

  5. Java集合类——Set、List、Map、Queue接口

    目录 Java 集合类的基本概念 Java 集合类的层次关系 Java 集合类的应用场景 一. Java集合类的基本概念 在编程中,常需要集中存放多个数据,数组是一个很好的选择,但数组的长度需提前指定 ...

  6. 牛客网Java刷题知识点之Java集合类里面最基本的接口有哪些

    不多说,直接上干货! https://www.nowcoder.com/ta/review-java/review?tpId=31&tqId=21086&query=&asc= ...

  7. java集合类框架的基本接口有哪些

    集合类接口指定了一组叫做元素的对象.集合类接口的每一种具体的实现类都可以以他自己的方式对元素进行保存和排序.有的集合允许重复的键,有些不允许. java集合类里面最基本 的接口: Collection ...

  8. Java集合类--温习笔记

    最近面试发现自己的知识框架有好多问题.明明脑子里知道这个知识点,流程原理也都明白,可就是说不好,不知道是自己表达技能没点,还是确实是自己基础有问题.不管了,再巩固下基础知识总是没错的,反正最近空闲时间 ...

  9. 做JavaWeb开发不知Java集合类不如归家种地

    Java作为面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储.但是使用数组存储对象方面具有一些弊端,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容 ...

随机推荐

  1. css 背景 background

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! background我们一般用到的的属性有: background-attachment:背景(图片)是否 ...

  2. 怎样通过混入(Mixin)实现多继承

    js不提供现成的多重继承的方法, 但可以通过Object.assign()来手动实现: function Father1(name){ this.name = name; } function Fat ...

  3. (六)Activiti之实现学生请假流程

    一.实现学生请假流程 1.1 用activiti插件生成bpmn和png文件 1.2 部署流程定义 package com.shyroke.activiti.firstActiviti; import ...

  4. Map集合中key不存在时使用toString()方法、valueOf()方法和强制转换((String))之间的区别

    1.toString()方法 底层代码 public String toString() { return this; } 其返回值为String类型的字符串本身 Map<String, Obj ...

  5. windows环境安装haproxy及初步配置负载均衡使用示例

    安装HaProxy 首先需要下载windows环境下需要文件,这里下载的是一个别人编译好的一个文件,这里省去了编译的过程,使用的版本是haproxy-1.7.8. 下载后直接解压到对应的目录下.示例( ...

  6. URL - Fiddler - IIS

    URL和URI URI:Uniform Resource Identifier,唯一标识一个网络资源 URL:Uniform Resource Locator,指向网络资源地址 URL是URI的子集, ...

  7. 查看SVN当前登录用户

    一般用户登录svn并记住用户密码后,下次再登录的时候将不需要输入用户密码,导致电脑使用着登录的时候,不知道到底登录的是个用户,只能将数据清除,现在给出查看登录用户的方法. 记录svn登录用户的文件,存 ...

  8. TLS1.3&TLS1.2形式化分析(二)

    1.下面是TLS1.2和TLS1.3握手协议过程 ,明显的可以看出存在不同 . 我们先说TLS1.2的握手过程明显是比TLS1.3的握手过多了一次.在TLS1.3中舍弃了之前RSA的协商过程,然后基于 ...

  9. skeleton directory: /etc/skel

    第一次接触这个词汇 还是在LFS8.2里面,感觉有点吓人.好好一个计算机操作系统,怎么搞出这个恐怖的术语.... 当使用useradd 或者其他命令创建用户的时候,/etc/skel这个目录下的文件. ...

  10. wav音频的剪切

    wav格式音频剪切功能的完美实现方案. import java.io.*; import javax.sound.sampled.*; public class AudioFileProcessor ...