java list变量_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(intindex, E element) {if (index > size || index < 0)throw newIndexOutOfBoundsException(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(intminCapacity) {if (elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

minCapacity=Math.max(DEFAULT_CAPACITY, minCapacity);

}

ensureExplicitCapacity(minCapacity);

}private void ensureExplicitCapacity(intminCapacity) {

modCount++;if (minCapacity - elementData.length > 0)

grow(minCapacity);

}private void grow(intminCapacity) {//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 Nodefirst;

transient Node last;

成员变量只有三个,主要存储了首尾Node元素,看一下Node结构:

private static class Node{

E item;

Nodenext;

Nodeprev;

Node(Node prev, E element, Nodenext) {this.item =element;this.next =next;this.prev =prev;

}

}

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

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

public void add(intindex, E element) {

checkPositionIndex(index);if (index ==size)

linkLast(element);elselinkBefore(element, node(index));

}

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

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

Node node(intindex) {//assert isElementIndex(index);

if (index < (size >> 1)) {

Node x =first;for (int i = 0; i < index; i++)

x=x.next;returnx;

}else{

Node x =last;for (int i = size - 1; i > index; i--)

x=x.prev;returnx;

}

}

从成员变量我们知道,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, Nodesucc) {//assert succ != null;

final Node pred =succ.prev;final Node newNode = new Node<>(pred, e, succ);

succ.prev=newNode;if (pred == null)

first=newNode;elsepred.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则更具有效率;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值