java集合-List简单介绍

List为一个接口,直接继承Collection接口,对比他们的接口变化:除了Collection接口中size(),isEmpty()等方法,其增加了基于下标index的一系列方法,摘抄部分接口方法:

get(int)

set(int, E)

add(int, E)

remove(int)

indexOf(Object)

lastIndexOf(Object)

subList(int, int)

我们简单看一下ArrayList,

首先看一下成员变量

    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    transient Object[] elementData;
    private int size;

elementData为内部实际存储元素的数组,即ArrayList是基于数组的存储结构,我们get(int),set(int,E)等方法,实质也是操作数组来实现;
看一下加入元素方法:

    public void add(int index, E element) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

主要做了输入数据合法性检查,容器扩容检查,数组复制,数组插入位置赋值,size尺寸增加;

我们从ensureCapacityInternal()方法开始:

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    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);
    }

关于容器扩容检查的几个方法,我们看一下主要流程,最终参数minCapacity的值为size+1,通过grow()方法,newCapacity其中一种尝试是赋值为elementData数组长度的1.5倍,并通过Arrays.copyOf()方法实现elementData数据最终扩容;

完成扩容检查之后,我们进行数组复制,因为此时elementData数组已经扩容,所以可以从index位置统一移动到index+1位置,预留出index位置;

最后我们把index位置赋值为我们add的元素,整个即完成来ArrayList在特定位置增加元素的过程;

我们在简单看一下LinkedList:

LinkedList除了具备List接口的所有特性,它还实现了Deque接口,可以先看List接口相关的;我们看一下成员变量:

    transient int size = 0;

    transient Node<E> first;

    transient Node<E> last;

成员变量只有三个,主要存储了首尾Node元素,看一下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;
        }
    }

是一个私有数据存储类,包含实际存储的元素item以及指向前后Node的变量;是一种基于链表结构的容器;

我们也看一下加入元素方法:

    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

主要包括输入参数检查,如果是末尾添加linkList(),如果不是末尾添加linkBefore();

主要看一下linkBefore()方法,输入参数node(index):

    Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

从成员变量我们知道,LinkedList不像ArrayList那样维护一个内部数组,而是通过包装类Node持有存入的元素和在它之前和之后的Node引用;所以当我们想要找到某一个元素时,只能够从成员变量的first开始位置的Node或者结束位置last的Node变量逐个逐个查找;通过node()方法可以看到,分析当index小于容器长度一半时,是从first位置开始遍历,由第一个Node的next引用可以找到第二个Node,第二个Node的next引用找下一个,直到小于index时的Node;

回到linkBefore()方法,我们已经找到index位置的Node,在以此为基础add进入一个新的的Node,即add进新的元素;

    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

我们简单看一下,主要目的是new一个新的Node对象newNode,newNode需要保存add进入容器的元素element,将prev和next分别赋值上一个Node和下一个Node,上一个Node即从传入的Node参数获取,下一个即传入参数Node本身,同时跟新传入Node的上一个引用指向新插入的newNode,最终完成了LinkedList指定位置add元素的整个流程;

从两种List集合的add方法的分析过程可以看出,删除和插入元素ArrayList涉及到内部数组的赋值移动,而LinkedList又涉及到内部遍历,效率都不是很好;如果我们想拿到具体位置的元素,ArrayList可以通过index索引直接得到,但是LinkedList需要从头部或者尾部逐个遍历才能拿到具体位置的元素;如果操作首尾元素,而linkedList则更具有效率;

原文地址:https://www.cnblogs.com/woshijinlei/p/12046837.html

时间: 2024-08-01 16:33:57

java集合-List简单介绍的相关文章

java反射机制简单介绍

1.字节码.所谓的字节码就是当java虚拟机载入某个类的对象时,首先须要将硬盘中该类的源码编译成class文件的二进制代码(字节码),然后将class文件的字节码载入到内存中,之后再创建该类的对象 2.java反射的基础是Class类(注意不是小写的class),Class类实例代表着内存中的一份字节码.常见的获取Class类对象的方法例如以下(第一种为对象的方法,另外一种为类的方法): Dog dog = new Dog(); Class dogClass = dog.getClass();

[Java 8 Lambda] java.util.stream 简单介绍

包结构例如以下所看到的: 这个包的结构非常easy,类型也不多. BaseStream接口 全部Stream接口类型的父接口,它继承自AutoClosable接口,定义了一些全部Stream都具备的行为. 由于继承自AutoClosable接口,所以全部的Stream类型都能够用在Java 7中引入的try-with-resource机制中,以达到自己主动关闭资源的目的.实际上,仅仅有当Stream是通过Socket,Files IO等方式创建的时候,才须要关闭它.对于来自于Collection

JAVA集合框架特征介绍

数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵活熟练地使用这些集合框架,可以很明显地提高我们的开发效率,当然仅仅会用还是不够的,理解其中的设计思想与原理才能更好地提高我们的开发水平.下面是自己对Java集合框架方面的学习总结. 一.概述 二.Collection接口 1.List 2.Set 3.Queue 三.Map接口 1.HashMap实

java随机数Reandom(简单介绍)

简单介绍 Java中存在着两种Random函数 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布. 二.java.util.Random Random()的两种构造方法: 1.Random():创建一个新的随机数生成器. 2.Random(long seed):使用单个 long 种子创建一个新

Object-c集合的简单介绍

一.简单介绍 NSArray/NSMutableArray NSSet/NSMutableSet NSDictionary/NSMutableDictionary NSArray.NSSet.NSDictionary是不可变的,创建的时候初始化 NSMutableArray.NSMutableSet.NSMutableDictionary是可变的 二.使用介绍 NSArray是有序的数组 NSMutableArray *myArray=[[NSMutableArray alloc] init];

Java提高篇—— 简单介绍Java 的内存泄漏

阅读目录 什么是内存泄漏? 为什么会发生内存泄漏? 如何预防内存泄漏? java最明显的一个优势就是它的内存管理机制.你只需简单创建对象,java的垃圾回收机制负责分配和释放内存.然而情况并不像想像的那么简单,因为在Java应用中经常发生内存泄漏. 本教程演示了什么是内存泄漏,为什么会发生内存泄漏以及如何预防内存泄漏. 回到顶部 什么是内存泄漏? 定义:如果对象在应用中不再被使用,但由于它们在其他地方被引用,垃圾回收却不能移除它们(这样就造成了很多内存不能释放,从而导致内存溢出的现象.译注).

java集合常用类介绍

List接口: 一:ArrayList private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private transient Object[] elementData; private int size; 用数组来存储元素,也就是基于 Object[]来管理元素,等于数组的加强版,在add()方法时先调用ensureCapacityIntern

转 java集合常用类 介绍

集合的结构如下图所示: 集合的两个顶级接口分别为:Collection和Map Collection下有两个比较常用的接口分别是List(列表)和Set(集),其中List可以存储重复元素,元素是有序的(存取顺序一致),可以通过List脚标来获取指定元素;而Set不可以有重复元素,元素是无序的. List接口中,比较常用的类有三个:ArrayList.Vactor.LinkedList. ArrayList :线程不安全的,对元素的查询速度快. Vector :线程安全的,多了一种取出元素的方式

java集合的简单使用

/* list接口      ArrayList 采用异步处理方式,性能高,但属于非线程安全      Vector    采用同步处理方式,性能低,但属于线程安全      当程序考虑线程安全的时候选Vector,其他选择ArrayList,速度快,性能高 set接口不能加入重复元素,(记忆:s开头same反而不同),但是可以排序   set接口的常用子类        散列存放:HashSet(哈希的话没有排序)        有序存放:TreeSet(有序的) Iterator接口  集合