一. ArrayList 初识

ArrayList是集合的一种实现,实现了接口List,List接口继承了Collection接口。

ArrayList 是java 中最常用的集合类型,这是因为它使用起来非常简单,而且它提供了非常丰富的功能,并且性能非常好,这里需要注意的是性能是以牺牲了线程安全为代价的,ArrayList 好用又很大一部分来自它的动态扩容,不像数组那样你需要提前计算好数组的大小,ArrayList 会随着元素的增加自动扩容。

虽然在其内部它并不是真正的弹性数组在不断增长,但它就像拥有一个具有初始容量(默认为长度为10的数组)的数组一样简单。当超过这个限制创建另一个数组,它是原始数组的1.5倍,旧数组中的元素被复制到新数组中。

ArrayList使用非常广泛,不论是数据库表查询,excel导入解析,还是网站数据爬取都需要使用到,了解ArrayList原理及使用方法显得非常重要。

下面就是ArrayList 的真实形态了

1. ArrayList 的说明书

在看说明书之前,我们还是先看一下整个类的继承关系

我们读一下源码,看看定义ArrayList的重要属性,当然我们还是习惯性的读一下类注释,让我们先有一个大概的认识,最后我们再通过例子,对它有一个精准的认识

 /*** Resizable-array implementation of the <tt>List</tt> interface.  Implements all optional list operations, and permits all elements, including <tt>null</tt>.  * 可变化的数组实现了list 接口,实现了list 的所有操作,并且允许插入所有的元素,包括null * In addition to implementing the <tt>List</tt> interface, this class provides methods to manipulate the size of the array that is used internally to store the list. * 除了实现了list 接口之外,还提供了在内部使用的,操作存储了list元素数组的大小的方法* (This class is roughly equivalent to <tt>Vector</tt>, except that it is unsynchronized.)* 这个类大致上和Vector 类似,除了这个类不是同步的* <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>, <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant time. * 上面这些方法的时间复杂度都是常数,其实就是O(1)* The <tt>add</tt> operation runs in <i>amortized constant time</i>,that is, adding n elements requires O(n) time. * add 方法 均摊时间复杂度是O(1),添加n 个元素的时间复杂度就是O(n)* All of the other operations run in linear time (roughly speaking).  The constant factor is low compared to that for the <tt>LinkedList</tt> implementation.* 所有其他的方法的时间复杂度都是线性的,* <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is the size of the array used to store the elements in the list.  It is always* at least as large as the list size. * 每一个ArrayList的实例都有一个容量,这个容量就是list 里面用来存储元素的数组的大小,它是和list 的大小是一样大的* As elements are added to an ArrayList,its capacity grows automatically. * 随着元素的添加,ArrayList 的大小在自动变化* The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.* 除了增加一个元素具有固定的均摊时间复杂度这一事实外,增长策略的细节没有被指定。* <p>An application can increase the capacity of an <tt>ArrayList</tt> instance before adding a large number of elements using the <tt>ensureCapacity</tt>* operation.  This may reduce the amount of incremental reallocation.* 应用程序可以在添加大量元素之前通过该指定ensureCapacity的操作来增加ArrayList的容量(其实就是通过构造方法),这样可以减少重新分配的次数(扩容的次数)* <p><strong>Note that this implementation is not synchronized.</strong> * 重点注意这个实现不是线程安全的* The list should be "wrapped" using the  {@link Collections#synchronizedList Collections.synchronizedList} method.  This is best done at creation time, to prevent accidental* unsynchronized access to the list:<pre> List list = Collections.synchronizedList(new ArrayList(...));</pre>* 如果需要线程安全的对象,可以使用Collections.synchronizedList对其进行包装,最好在创建时执行此操作,以防止意外的对列表的非同步访问,List list = Collections.synchronizedList(new ArrayList(...))* <p><a name="fail-fast"> The iterators returned by this class's {@link #iterator() iterator} and {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>* 这个类的iterator() 和 listIterator() 方法返回的迭代器都是fail-fast 的* if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own {@link ListIterator#remove() remove} or {@link ListIterator#add(Object) add} methods, the   iterator will throw a {@link ConcurrentModificationException}. * 除了ListIterator#remove()和ListIterator#add(Object) 这两个方法之外的任何情况下,这个类对象的iterator在创建之后的任何时间,发生了结构上的修改则会抛出ConcurrentModificationException 的异常* @author  Josh Bloch* @author  Neal Gafter* @since   1.2*/​public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {/*** Default initial capacity.  默认的初始容量*/private static final int DEFAULT_CAPACITY = 10;​/*** Shared empty array instance used for empty instances.* 指定参数初始容量,但是初始容量是0的时候 * elementData= EMPTY_ELEMENTDATA*/private static final Object[] EMPTY_ELEMENTDATA = {};​/*** Shared empty array instance used for default sized empty instances. We* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when* first element is added.* 无参构造的时候使用 elementData= DEFAULTCAPACITY_EMPTY_ELEMENTDATA*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};​/*** The array buffer into which the elements of the ArrayList are stored.* The capacity of the ArrayList is the length of this array buffer. * 其实就是实际存储元素的数组* Any empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* will be expanded to DEFAULT_CAPACITY when the first element is added.* 如果是 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 则在第一次添加元素的时候则会扩容到DEFAULT_CAPACITY*/transient Object[] elementData; // non-private to simplify nested class access​/*** The size of the ArrayList (the number of elements it contains).* 实际存储的元素多少* @serial*/private int size;}//默认创建一个ArrayList集合List<String> list = new ArrayList<>();/*** Constructs an empty list with an initial capacity of ten.*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}//创建一个初始化长度为100的ArrayList集合List<String> initlist = new ArrayList<>(100);​public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);}}//将其他类型的集合转为ArrayListList<String> setList = new ArrayList<>(new HashSet());​/*** Constructs a list containing the elements of the specified* collection, in the order they are returned by the collection's* iterator.** @param c the collection whose elements are to be placed into this list* @throws NullPointerException if the specified collection is null*/public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}Object[] toArray();public class CustomList<E> extends ArrayList {@Overridepublic Integer [] toArray() {return new Integer[]{1,2};};public static void main(String[] args) {Object[] elementData = new CustomList<Integer>().toArray();System.out.println(elementData.getClass());System.out.println(Object[].class);System.out.println(elementData.getClass() == Object[].class);}}class [Ljava.lang.Integer;class [Ljava.lang.Object;falsepublic static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {    T[] copy = ((Object)newType == (Object)Object[].class)? (T[]) new Object[newLength]: (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));return copy;}List<String> list = new ArrayList<>(10);list.add('牛魔王');list.add('蛟魔王');...list.add('美猴王');/*** Appends the specified element to the end of this list.* 添加一个元素到列表的末尾* @param e element to be appended to this list 被添加的元素* @return <tt>true</tt> (as specified by {@link Collection#add}) 固定的返回值 True*/public boolean add(E e) {// 保证容量,这个就是在添加元素之前要要保证内部的数组大小足够可以容纳该元素 ensureCapacityInternal(size + 1);// Increments modCount!!elementData[size++] = e;return true;}private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private static int calculateCapacity(Object[] elementData, int minCapacity) {// 这里有个注意点就是,无参数构造的话,elementData =DEFAULTCAPACITY_EMPTY_ELEMENTDATA 也就是说这里会返回 10,但是有参构造的话,不满足这个条件,也就是如果是无参构造的话,在第一次添加元素的时候将直接扩容到DEFAULT_CAPACITYif (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}// 否则的话则是有参构造或者不是第一次添加元素,那么这里返回的就是size+1,也就是说扩容到所需的szie+1 即可return minCapacity;}private void ensureExplicitCapacity(int minCapacity) {modCount++;// 不满足要求的容量则进行扩容,也就是数组大小不够了if (minCapacity - elementData.length > 0)grow(minCapacity);}/*** Increases the capacity to ensure that it can hold at least the number of elements specified by the minimum capacity argument.* 增加容量以保证至少可以存储输入参数那么多的元素* @param minCapacity the desired minimum capacity 确定需要最少容量的参数*/private void grow(int minCapacity) {// overflow-conscious codeint 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);}arrayList.add(1,"a");arrayList.addAll(new HashSet());/*** Inserts the specified element at the specified position in this list. Shifts the element currently at that position (if any) and* any subsequent elements to the right (adds one to their indices).* 插入指定元素到指定位置,如果当前待插入的位置有元素,则需要右移当前元素和其后的元素* @param index index at which the specified element is to be inserted* @param element element to be inserted* @throws IndexOutOfBoundsException {@inheritDoc}*/public void add(int index, E element) {// 检查位置的合法性rangeCheckForAdd(index);// 扩容ensureCapacityInternal(size + 1);  // Increments modCount!!// 移动当前位置和其后置的元素System.arraycopy(elementData, index, elementData, index + 1,ize - index);// 存储该元素elementData[index] = element;// 修改元素数目size++;}/*** A version of rangeCheck used by add and addAll.*/private void rangeCheckForAdd(int index) {if (index > size || index < 0)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}public E set(int index, E element) {rangeCheck(index);E oldValue = elementData(index);elementData[index] = element;return oldValue;}// 需要注意的是这里不会给你扩容的,如果你越界直接抛出异常private void rangeCheck(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}public E get(int index) {// 当然也是检测下标是否越界rangeCheck(index);return elementData(index);}E elementData(int index) {return (E) elementData[index];}public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index, numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue;}public boolean remove(Object o) {if (o == null) {for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false;}List<String> cityList = new ArrayList<>(2);cityList.removeIf((String name )->name.equalsIgnoreCase("Bangalore"));@Testpublic void itrator(){List<String> cityList = new ArrayList<>(2);cityList.add("London");cityList.add("Paris");cityList.add("Bangalore");cityList.add("Istanbul");Iterator<String> itr = cityList.iterator();while(itr.hasNext()){String city = itr.next();if(city.equals("Paris")){cityList.remove(city);}System.out.println(city);}}LondonParisjava.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)at java.util.ArrayList$Itr.next(ArrayList.java:859)@Testpublic void itrator2(){List<String> cityList = new ArrayList<>(2);cityList.add("London");cityList.add("Paris");cityList.add("Bangalore");cityList.add("Istanbul");Iterator<String> itr = cityList.iterator();while(itr.hasNext()){String city = itr.next();if(city.equals("Paris")){itr.remove();}else {System.out.println(city);}}}/*** Removes all of the elements from this list.  The list will* be empty after this call returns.*/public void clear() {modCount++;​// clear to let GC do its workfor (int i = 0; i < size; i++)elementData[i] = null;size = 0;}

  1. ArrayList 就是一个实现了List接口的课自动扩容的数组,当添加元素的时候它会尝试扩容,扩容的标准是变为原来的1.5倍,当删除元素的时候,它会左移元素,避免数组出现"空位"
  2. ArrayList 都有容量,容量就是ArrayList里面数组的大小
  3. ArrayList 是一个有序的集合,它的维持的顺序就是元素的插入顺序(可以对比HashMap)
  4. ArrayList 可以存储重复值和null值
  5. ArrayList 是快速失败的,在遍历的同时当集合被修改后会抛出ConcurrentModificationException,可以使用Iterator 的删除方法来避免这个问题
  6. ArrayList 不是线程安全的,如果你想在多线程环境中使用,可以使用Vector 或者它的线程安全包装类

四. 总结

Traverse - 遍历的时间时间复杂度是O(n),也就是依赖于Capacity 的大小,如果你比较重视遍历的性能,就请不要不要给它设置一个很大的初始容量

Removing an element- 当你使用 remove(int index) 它的时间复杂度是 O(n - index) ,因为它涉及到移动元素

Retrieving an element- 当你使用get(int index) 的时候,它的时间复杂度是 O(1),因为数组可以直接根据下标进行定位

Adding an element- 如果你使用的实 add(E e) 方法添加一个元素到ArrayList末尾 ,它的时间复杂度 O(1);但是当空间不足引发扩容的时候,会导致新建数组然后拷贝数据,这个时候它的时间复杂度 O(n) ;当你使用 add(int index, E element)的时候它的算法复杂度是 O(n - index) 也就是 O(n)

三. ArrayList 的性能

这里给大家一个思考题,为什么要遍历呢,而不是先创建一个同等大小的数组,然后将数组当前设置为null呢,其实我觉得也可以,而且更快

clear():集合清空,通过遍历底层数组elementData,设置为null

contains(Object o):是否包含某个元素,通过遍历底层数组elementData,通过equals或==进行判断

isEmpty():是否为空,通过定义在ArrayList中的私有变量size得到

size() : 获取集合长度,通过定义在ArrayList中的私有变量size得到

7. 其他方法

当然如果你就想在遍历的过程中删除元素,也不是不行,调用iterator 的remove 方法即可,然后ArrayList 中的元素也会被删除的

输出结果

这里主要演示一下它的快速失败属性

6. iterator 方法

当然 ArrayList 还给我们提供了另外一个方法,那就是removeIf(),它是一个函数式接口

删除ArrayList中的值对象,其实和通过下标删除很相似,只是多了一个步骤,遍历底层数组elementData,通过equals()方法或 == (特殊情况下)来找到要删除的元素,获取其下标,调用remove(int index)一样的代码即可。

5. remove(Object o)

如remove(10),找到的元素为“美猴王”,那么移动位数 = 12-10-1 = 1;此时将原本在第12个位置上(数组下标为11)的“白骨精”往前移动一位,同时设置elementData[11] = null;这里通过设置null值让GC起作用。

其次计算了数组中需要移动的位数 size - index - 1,那么很明显我们可以得出待删除的是最后一个元素的话,移到位数为0,否则移动位数大于0,那么通过数组元素的拷贝来实现往前移动相应位数。

通过源码我们可以看到首先获取了待删除的元素,并最终返回了。这里的下标和数组一样,都是从0开始的

首先说一下ArrayList通过下标删除的方法,我们看一下源码

4. remove(int index)

调用get(6)返回”哪吒“。

ArrayList中get方法也非常简单,通过下标查找即可,同时需要进行了类型转换,因为数组为Object[],前提是需要判断传入的数组下标是否越界。

3. get(int index)

返回值“猕猴王”,当前数组中数据:

因为ArrayList底层是由数组实现的,set实现非常简单,调用 set(8, "猪八戒") 通过传入的数字下标找到对应的位置,替换其中的元素,前提也需要首先判断传入的数组下标是否越界。将“猕猴王”替换为“猪八戒”

2. set(int index, E element)

其实走到这个你就会发现,ArrayLis 是一个密集的数据结构,因为它不会差生空位,你可以对比HashMap

这里的检查方法也是比较简单的,就是下标必须是已经存在的元素的位置

这里我还是对添加到指定位置进行简单说明一下,我们还是接着看源码

当然ArrayList 的add 也存在很多变体的方法,例如下面的两个方法,你可以研究一下,当然添加元素到指定位置的方法,和set 有点类似,只不过set 是覆盖,add 可能需要移动元素

这里需要注意一下的是扩容这个过程,或者说是计算容量的过程,如果你是无参构造则一次性扩容到DEFAULT_CAPACITY,如果不是则都是根据所需容量(size+1)进行判断是否要扩容,如果是的话,则扩容为原来的1.5倍

当添加一个新元素到ArrayList的时候,首选会验证一下ArrayList时候有足够的容量了来存储新的元素,如果不够的话则会创建一个新的数组是原来数组大小的1.5 倍,然后copy 数据到新的数组

总结

add("铁扇", 0); //将数组中的元素各自往后移动一位,再将“铁扇”放到第一个位置上;

addAll(list..七个葫芦娃); //将集合{七个葫芦娃}放到"白骨精"后,很明显当前数组的容量已经不够,需要扩容了,不执行该句代码了;addAll(list..哪吒三兄弟, 4);//从第五个位置将“哪吒三兄弟”插进去,那么数组第五个位置后的元素都需往后移动三位,数组按规则扩容为18。

指定了插入位置的,会通过rangeCheckForAdd(int index)方法判断是否数组越界

当然add 方法还有很多变体,如果你感兴趣可以自己研究一下,因为add方法指定index的时候和set 方法很类似,所以你可以看完下面的set 方法再去看add 方法的变体

因为最开始定义了集合容量为10,故而本次不会进行扩容,直接将第8个位置(从0开始,下标为7)设置为“白骨精”,这时Object[] elementData中数据如下:

int newCapacity = (oldCapacity * 3)/2 + 1;

这里需要注意一个问题,在老版本的代码中,它的计算公式是这样的

扩容规则为 数组小容量 + (数组当前容量 / 2),即数组当前容量 * 1.5,当然有最大值的限制。如果计算出来的结果也就是数组当前容量 * 1.5 还是不足的话,直接使用newCapacity作为最小容量

这里首先确定了Object[]足够存放添加数据的最小容量,然后通过 grow(int minCapacity) 来进行数组扩容

拿到返回的的capacity 之后,进行判断 确保足够的容量(ensure explicit capacity)

首先调用了下面的方法计算容量,见名知意吧(calculate Capacity),如果elementData 不是空的话,直接返回minCapacity,也就是szie+1,是空的话就返回Math.max(DEFAULT_CAPACITY, minCapacity) 也就是10

这里如果是首次添加元素的话,szie=0 然后minCapacity=1 的

首先通过 ensureCapacityInternal(size + 1) 来保证底层Object[]数组有足够的空间存放添加的数据,然后将添加的数据存放到数组对应的位置上,我们看一下是怎么保证数组有足够的空间?

我们通过源码来看一下add("白骨精")到底发生了什么

1. add(E element)

Object[] elementData中数据如下:

首先定义了一个ArrayList,

ArrayList有很多常用方法,add,addAll,set,get,remove,size,isEmpty等

二. ArrayList常用方法

无参构造时候但是initialCapacity=0的时候,EMPTY_ELEMENTDATA 其实主要是为了区分elementData=它是无参构造的赋值,还是有参但是是0的时候的赋值

EMPTY_ELEMENTDATA

无参构造时候,elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA 其实主要是为了区分elementData=它是无参构造的赋值,还是有参但是是0的时候的赋值

DEFAULTCAPACITY_EMPTY_ELEMENTDATA

ArrayList 背后真正存储数据的结构,也就是存储数据的数组,可以说是ArrayList背后的巨人

elementData

首先说明一下,ArrayList 中没有这样的变量,但是我把它单独拿出来说,是想强调一点,CAPACITY 表示的实数组的大小,而不是实际存储的元素个数——size,它表示的实存储能力,size 表示已经使用

CAPACITY

默认的数组大小,就是在你不指定minCapacity变量的时候,它将使用DEFAULT_CAPACITY 作为数组的大小(但是需要注意的是它是在第一次添加元素的时候在使用的),而不是像你指定了minCapacity在构造方法中那样,在创建ArrayList 的过程中就创建了

DEFAULT_CAPACITY

实际存储的元素个数,也就是数组中存储的元素个数,而不是数组的大小

size

3. ArrayList 内部构成

我们发现定义了一个新的数组,将原数组的数据拷贝到了新的数组中去。

接着说,如果传入的集合类型和我们定义用来保存添加到集合中值的Object[]类型不一致时,ArrayList做了什么处理?读源码看到,调用了Arrays.copyOf(elementData, size, Object[].class);,继续往下走

执行结果:

我们发现返回的确实是Object[],那么为什么还会有这样的判断呢?
如果有一个类CustomList继承了ArrayList,然后重写了toArray()方法呢。。

if (elementData.getClass() != Object[].class),
给出的注释是:c.toArray might (incorrectly) not return Object[] (see 6260652),即调用toArray方法返回的不一定是Object[]类型,查看Collection接口的定义

注意:在传入集合的ArrayList的构造方法中,有这样一个判断

当集合是一个空的集合的话,elementData = EMPTY_ELEMENTDATA和指定0是initialCapacity的效果一样

构造一个包含指定集合元素的列表,其顺序由集合的迭代器返回。当传入的集合参数为空的话,抛出NullPointerException,因为它会调用该集合的toArray 方法,和HashTable 里面调用key 的hashcode 方法的原理一样

其他集合作为参数

创建一个空的指定容量的list

指定初始容量

创建一个空的使用默认容量的list(默认是10)

无参构造

2. ArrayList 的构造方法

  • 例如当调用new ArrayList<>()时,将一个空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给了elementData,这个时候集合的长度size为默认长度0;
  • 例如当调用new ArrayList<>(100)时,根据传入的长度,new一个Object[100]赋值给elementData,当然如果玩儿的话,传了一个0,那么将一个空数组 EMPTY_ELEMENTDATA 赋值给了elementData;
  • 例如当调用new ArrayList<>(new HashSet())时,根据源码,我们可知,可以传递任何实现了Collection接口的类,将传递的集合调用toArray()方法转为数组内赋值给elementData;

其实源码里面已经很清晰了,底层是一个Object[],添加到ArrayList中的数据保存在了elementData属性中。

arraylist转int数组_深度剖析Java集合之ArrayList相关推荐

  1. arraylist转int数组_五千字的数组拓展,面试官对我竖起大拇指喊停

    目录 为什么数组下标从0开始? 数组定义 为什么这么下定义? 定义数组的三种方式 从 ArrayList 源码看数组增删改查 初始化 增加 删除 修改 查找 数组和容器 数组时间复杂度 数组插入,删除 ...

  2. java定义int数组_怎样用java定义一个int数组

    展开全部 数组:是一组相关变量的集合数组是一组相关数据的集合,一个数组实际上就是32313133353236313431303231363533e4b893e5b19e31333363373731一连 ...

  3. java 集合接口原理_图文剖析java集合框架—Set接口

    Map接口图补充待续 继上一节讲解了List接口的常用实现类以及源码的一些分析,这节将讲解集合中的Set接口. HashSet: 底层原理:哈希表结构存储.对集合的迭代次序不作任何保证; 允许元素nu ...

  4. 深度剖析Java集合之ArrayDeque

    ArrayDeque ArrayDeque是Deque接口的一个实现,使用了可变数组,所以没有容量上的限制.同时,ArrayDeque是线程不安全的,在没有外部同步的情况下,不能再多线程环境下使用. ...

  5. 深度剖析Java数据结构之迭代器(Iterator)

    一.什么是迭代器 我们知道,JVM是用C/C++编写的.在百度百科中,迭代器是解释是迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定 ...

  6. java map按照value排序_基础:Java集合需要注意的 5 个问题

    点击上方 Java后端,选择 设为星标 优质文章,及时送达 Java集合中的List.Set和Map作为Java集合食物链的顶级,可谓是各有千秋.本文将对于List.Set和Map之间的联系与区别进行 ...

  7. 从源码看Java集合之ArrayList

    Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...

  8. 深度剖析Java数据结构之表(三)——ArrayList泛型类的实现

    为了避免与类库中的ArrayList类重复,在这里,使用的类名为ArrayListDemo.在Java中,ArrayList泛型类是继承AbstractList泛型类的,并且实现了List<E& ...

  9. 【源码阅读】Java集合之一 - ArrayList源码深度解读

    Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,从ArrayList开始第一篇. ---@pdai JDK版本 ...

最新文章

  1. UITableView嵌套WKWebView的那些坑
  2. gitlab数据迁移
  3. 世界上最百变的人不是女友,竟然是......
  4. 2011年中国程序员薪水调查报告
  5. System.Text.Json 中的字符编码
  6. php prettyprinter,gdb运行时错误:prettyprinter已注册:libstdc++v6
  7. Sublime Text3自定义快捷键
  8. itunes备份包括哪些内容_建筑施工资质维护主要包括哪些内容?
  9. 使用nginx负载均衡的webservice wsdl访问不到_谁说前端不用懂,Nginx 反向代理与负载均衡(超实用)...
  10. mysql x锁 u锁_讲解更新锁(U)与排它锁(X)的相关知识
  11. 文字不间断横向滚动 代码 IE FireFox兼容代码
  12. SQL 个人所学目录
  13. 版本管理SVN的使用——SmartSVN使用
  14. SQLServer 2008 下载地址(微软官方网站)
  15. 35岁高以翔过劳猝死:人生无常,求各位项目经理少加点班吧
  16. 大文件传输的三种方式
  17. linux改d5000默认路径,linux相关指令和d5000基础操作.pdf
  18. linux 进程无法启动,linux6.*无法正常启动has进程解决方案
  19. 下面不是计算机网络面临的主要威胁是,网络安全复习题2
  20. App三种启动场景:冷启动、热启动、温启动

热门文章

  1. 娓娓道来!那些BERT模型压缩方法(一)
  2. 【论文复现】Character-level Convolutional Networks for Text Classification
  3. 吴恩达|机器学习作业6.1.SVM建立垃圾邮件分类器
  4. python语言案例教程 单元测试_python单元测试unittest实例详解
  5. c语言 单词变复数_关于C语言中的Complex(复数类型)和imaginary(虚数类型)
  6. phpstudy运行PHP项目出现404怎么办?
  7. 若依如何调整首页左侧菜单栏宽度?
  8. Windows系统中使用SSH服务端和客户端
  9. [Android系列—] 1. Android 开发环境搭建与Hello World
  10. web小知识与问题串烧(html,css,js)