ArrayList类的注解阅读


/**
* Resizable-array implementation of the <tt>List</tt> interface. Implements
* all optional list operations, and permits all elements, including
* <tt>null</tt>. 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. (This class is roughly equivalent to
* <tt>Vector</tt>, except that it is unsynchronized.) 这是一个实现了List接口的可变长度的数组。实现了list接口中的所有方法,允许存放所有的元素,包括null。除了实现list接口,该类还提供了一些方法来操作数组的大小,此数组被用来存储list的数据。(这个类和vector大致相当,除了它是线程不安全的)
  • ArrayList底层实现是数组,可存放重复数据,包括null,线程不安全
 *
* <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. The <tt>add</tt> operation runs in <i>amortized constant time</i>,
* that is, adding n elements requires O(n) time. 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.
* size(),isEmpty(),get(),set()方法使用的一个恒定时间(一个方法具有恒定的执行时间的,也就是代码不会因为问题规模n的变化而发生变化,时间复杂度记为O(1))。add操作花费恒定分摊时间,即插入n个元素需要o(n)的时间。 粗略的来说所有其他操作都以线性时间运行。(即这些操作与元素的个数成线性关系,操作的时间复杂度o(n))。这些操作与LinkedList实现相比,常数因子较低。
  • 底层为数组结构,相对于LinkedList效率较高
 * <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. As elements are added to an ArrayList,
* its capacity grows automatically. The details of the growth policy are not
* specified beyond the fact that adding an element has constant amortized
* time cost.
*
每个ArrayList的实例对象都有一个容量(capacity)。这个容量就是这个list中用来存储元素的数组的大小。它至少和list的大小一样大。当有元素被增加到集合中时,它的容量会自动增加。除了要求添加一个元素的效率为“恒定分摊时间”,对于具体实现的细节没有特别的要求。 * <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()方法来增加集合的容量。这或许能够减少扩容增加量的大小。
 * <p><strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access an <tt>ArrayList</tt> instance concurrently,
* and at least one of the threads modifies the list structurally, it
* <i>must</i> be synchronized externally. (A structural modification is
* any operation that adds or deletes one or more elements, or explicitly
* resizes the backing array; merely setting the value of an element is not
* a structural modification.) This is typically accomplished by
* synchronizing on some object that naturally encapsulates the list.
* 注意这个实现类是非同步的。如果有多个线程同时操作一个ArrayList的实例。然后,至少有一个线程修改了list的结构,就必须在外部保证它的线程同步。(结构修改指的是增加或者删除一个或多个映射;如果仅仅是更改已经存在的
key和value值,不算做结构修改)。这通常需要在一个被封装好的list对象上,使用同步进行操作。
  • ArrayList是非同步的,线程不安全的
 * If no such object exists, 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对象进行一些线程不同步的操作。举个例子:List list = Collections.synchronizedList(new ArrayList(...));
  • 尽管有一个线程安全的类Vector和ArrayList结构类似,但是我们在需要保证线程安全时依然不会使用Vector这个类(过时的类),而是使用 Collections.synchronizedList()方法来包装得到一个线程安全的list对象。
 * <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>
* 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}. Thus, in the face of
* concurrent modification, the iterator fails quickly and cleanly, rather
* than risking arbitrary, non-deterministic behavior at an undetermined
* time in the future.
* 该类的集合视图方法返回的迭代器是fail-fast机制的:在迭代器被创建后,如果list对象被结构化修改后,无论在何时,使用何种方法(除了迭代器本身的remove方法和add方法)来修改它,都会抛出ConcurrentModificationException.因此,面对并发修改操作时,迭代器会迅速且清晰地报错.而不是冒着在不确定的时间做不确定的操作的风险.
  • fail-fast,它是Java集合中的一种错误检测机制。某个线程在对collection进行迭代时,不允许其他线程对该collection进行结构上的修改。否则程序就会抛出ConcurrentModificationException 异常。快速终止操作

* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
* as it is, generally speaking, impossible to make any hard guarantees in the
* presence of unsynchronized concurrent modification. Fail-fast iterators
* throw {@code ConcurrentModificationException} on a best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
* exception for its correctness: <i>the fail-fast behavior of iterators
* should be used only to detect bugs.</i> 注意,迭代器的fail-fast行为是不能保证的.一般来说,保证非同步的同步操作是不太可能的.在最优基础上,Fail-fast迭代器会抛出ConcurrentModificationException.因此,写一个为了自身正确性而依赖于这个异常的程序是不对的.迭代器的fail-fast行为应该只是用来检测bug而已.
  • 我们要主动封装list以便进行同步操作,程序要要避免此异常而不是使用此异常

ArrayList类的定义

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 继承的类

    AbstractList:抽象类,只需知道此类是List接口的简单通用实现

  • 实现的接口

    List:不多说了


    RandomAccess:(标记接口)代表支持随机访问

    Cloneable:(标记接口)代表 Object.clone() 方法可以合法地对该类实例进行按字段复制。(没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常)

    java.io.Serializable(标记接口)

属性的定义

    protected transient int modCount = 0;

  • 这是父类AbstractList的一个属性 :用于记录列表结构被修改的次数。每次列表结构被修改都会modCount++

    为什么要记录此数据呢?

    在线程不安全的集合中,正如上面所说:迭代器采用了fail-fast机制。而fail-fast机制触发原理就是比对expectedModCount 和 modCount 是否相等,不相等就报ConcurrentModificationException异常

    此处不理解没关系,后面会讲迭代器方法的源码时,就会明白了
/**
* Default initial capacity.
* 初始默认容量 为 10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*
* 指定该ArrayList容量为0时,返回该空数组。
*/
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.
*
* 用于默认大小的空实例的共享空数组实例。
* 这个空数组的实例用来给无参构造使用。当调用无参构造方法,返回的是该数组。
* 将此与EMPTY_ELEMENTDATA区分开来,以便了解在添加第一个元素时要增加多少容量。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • EMPTY_ELEMENTDATA 和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA都是表示空数组实例

    区别在于:

    EMPTY_ELEMENTDATA 是用户指定初试容量为0时 使用它

    DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是默认创建初始容量为10的空数组,被无参构造器使用

    将此与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.
*
* 存储ArrayList元素的数组缓冲区
* ArrayList的容量(capacity)就是是此数组缓冲区的长度。
* 声明为transient 不会被序列化
* 非私有 是为了方便内部类调用
*/
transient Object[] elementData; // non-private to simplify nested class access
  • 该值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入ArrayList中时, 数组将扩容至DEFAULT_CAPACITY。这也印证了为什么区分EMPTY_ELEMENTDATA,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
/**
* The size of the ArrayList (the number of elements it contains).
*
* List中元素的个数
*/
private int size;
  • 仅仅表示 该list包含的元素的个数,和数组容量没有任何关系

这里提一点:前面提到size()方法时间复杂度为O(1),是因为它将size存储起来了,牺牲了空间提高了效率。

ArrayList构造器

ArrayList有三个构造器

创建一个指定存储容量的空序列

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);
}
}
  • 指定的initialCapacity

    >0时,创建的序列容量为initialCapacity

    ==0时,创建的是 EMPTY_ELEMENTDATA

    <0时,会报异常
无参构造,创建一个初始容量为10 的空序列

public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
  • 此处使用的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA

遵循集合的约定 提供 一个可将Collection转换为ArrayList的构造器
这些元素是按照该 Collection 的迭代器返回它们的顺序排列的。 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;
}
}
  • 注意:toArray的方法返回的类型不一定是Object[] 这是jDK的bug,两个类之间有继承关系时,JDK允许向上转型(子类赋值给父类)而 向下转型(父类赋值给子类)是不允许的。为了解决这个问题需要检验运行时类型使用Arrays.copyOf将其转为Object[]类型

核心方法


/**
* Trims the capacity of this <tt>ArrayList</tt> instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an <tt>ArrayList</tt> instance.
*
* 将ArrayList的容量设置为当前size的大小,应用可以使用此方法最小化实例的存储空间
*
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
  • 注意:首先需要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不需要每次都进行扩容操作。此操作修改了列表结构,所以modCount++;

/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* 如有必要,增加此ArrayList实例的容量,以确保它至少可以容纳由minCapacity参数指定的元
* 素数。
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY; if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
} private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}
  • ensureCapacity方法中,minExpand 表示最小扩容量, minCapacity表示最小容量,在这里分了两种情况

    此实例 是默认大小的ArrayList,最小扩容量为DEFAULT_CAPACITY 否则为 0;然后比较minCapacity 和 minExpand,如果期望的最小容量比最小扩容量小就不扩容,反之使用minCapacity进行扩容

ensureCapacityInternal方法,数组容量检查,不够时则进行扩容,只供类内部使用,例如add(),addAll()等方法时会调用此方法进行容量检验,此时minCapacity 通常为size+n

    private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
// 只有最小容量比当前容量大时才会进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} /**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*
* 最大存储容量
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /**
* 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 code
int oldCapacity = elementData.length;
// 先预先扩容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 主要判断 预期最小容量 minCapacity 是否大于 MAX_ARRAY_SIZE
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

总结:

  1. 只有最小容量比当前容量大时才会进行扩容;
  2. 扩容操作时,会预先把容量扩容至自身容量的1.5倍(预扩容)(使用的是oldCapacity + (oldCapacity >> 1)),然后于需要的最小容量minCapacity进行比较,选其最大值;
  3. 最终需要的容量会判断是否超过数组最大容量MAX_ARRAY_SIZE,1.没有超过 ——> 生成新的容量数组;2.超过了 ——> 会进行判断(1.是需要的最小容量超过了MAX_ARRAY_SIZE ——> 最终容量设为Integer.MAX_VALUE; 2.还是预扩容超过了MAX_ARRAY_SIZE ——> 最终容量设为MAX_ARRAY_SIZE) ——> 生成新的容量数组;
  4. 使用最大容量MAX_ARRAY_SIZE时,要注意因为某些VM会在数组中保留一些头字,可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
  5. minCapacity<0时也会触发MAX_ARRAY_SIZE,但这种情况在我的认知下不会发生,可能是严谨的做法,安全检查;

普通方法


public boolean contains(Object o) {
// 借用indexOf的方法看是否存在
return indexOf(o) >= 0;
} // 实质就是遍历数组,使用Object的equals方法,返回-1为不存在此元素,lastIndexOf()方法就是反向遍历
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
} public boolean add(E e) {
// 检验是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 先在index=size的位置赋值e,再将ArrayList的size增加一位
elementData[size++] = e;
return true;
} /**
* 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,
size - index);
elementData[index] = element;
size++;
}

总结:

  1. add()一个参数直接加在数组最后
  2. add(index, element) 使用System.arraycopy()将index的位置空出来,将值赋值过去。System.arraycopy为 JVM 内部固有方法,它通过手工编写汇编或其他优化方法来进行 Java 数组拷贝,这种方式比起直接在 Java 上进行 for 循环或 clone 是更加高效的。数组越大体现地越明显。
    

    /**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
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); // 将数组最后一位 置 null,等待垃圾回收机制来回收
elementData[--size] = null; // clear to let GC do its work return oldValue;
} public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
} private class SubList extends AbstractList<E> implements RandomAccess {

迭代器(iterator&ListIterator)实现

ArrayList中的迭代器实现对AbstractList中的迭代器进行了优化

/**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* 按原有list的顺序返回一个迭代器,遵循fail-fast机制。
*
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
} /**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
// 后游标:指向下一个元素,等于下一个元素的索引值
int cursor; // index of next element to return
// 前游标:指向当前元素,等于当前元素索引值,-1代表在最开始,还未指向元素
int lastRet = -1; // index of last element returned; -1 if no such
// 将预期修改次数 和 实际修改次数 保持相等
int expectedModCount = modCount; // 是否有下一个元素
public boolean hasNext() {
return cursor != size;
} @SuppressWarnings("unchecked")
public E next() {
// 检查 预期修改次数 和 实际修改次数 是否相等——>数据结构是否改变
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1; // 后游标右移
return (E) elementData[lastRet = i];
} public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
// 调用ArrayList的remove
ArrayList.this.remove(lastRet);
// remove之后 后游标左移
cursor = lastRet;
// 重制前游标
lastRet = -1;
// 并且会使预期修改次数 和 实际修改次数 保持相等
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} // 检查 实际修改次数 和 预期修改次数是否相等
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
  • 总结:

    使用迭代器便利的时候,remove元素时,要使用Iterator.remove(),虽然其本质也是调用ArrayList的remove()的方法,只是为了使 modCount,expectedModCount 保持相等,否则会报ConcurrentModificationException()异常
/**
* Returns a list iterator over the elements in this list (in proper
* sequence), starting at the specified position in the list.
* The specified index indicates the first element that would be
* returned by an initial call to {@link ListIterator#next next}.
* An initial call to {@link ListIterator#previous previous} would
* return the element with the specified index minus one.
*
* <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
} /**
* Returns a list iterator over the elements in this list (in proper
* sequence).
*
* <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @see #listIterator(int)
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
} /**
* An optimized version of AbstractList.ListItr
*/
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
} public boolean hasPrevious() {
return cursor != 0;
} public int nextIndex() {
return cursor;
} public int previousIndex() {
return cursor - 1;
} @SuppressWarnings("unchecked")
public E previous() {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i;
return (E) elementData[lastRet = i];
}
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1; // 后游标右移
return (E) elementData[lastRet = i]; public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} public void add(E e) {
checkForComodification(); try {
int i = cursor;
// 在当前元素的后面加入此元素
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
// add 操作会导致 modCount++,所以这边要保持相等
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
  • remove和add操作成功后 lastRet都会重新赋值为-1,并且会执行expectedModCount = modCount操作,以防ConcurrentModificationException;

  • ListItr继承于Itr,增加了previous()等一些方法,最大不同是游标cursor可以向前移动了。

  • 注意:执行过next()方法后再执行previous(),当前元素并没有改变(lastRet没有变),只是cursor进行了了改变,不要进行常规思考 previous()操作就是当前元素向前移动,next()就是当前元素向后移动,准确来说是cursor进行前后移动,进行previous()操作时 lastRet始终等于cursor,next()操作时cursor始终比lastRet大1

最后声明

  源码版本为JDK1.8,只是对日常使用的基本操作的源码进行了分析,对于1.8的新特性并没有涉及,等将主要集合类源码分析完后,会专门出一篇分析一下1.8中集合的新特性;

  有建议或着问题的,请在文末留言,本人水平有限,有错误或理解偏差,还请各位多多指导和见谅,如若转载,请表明出处;

ArrayList源码阅读笔记(1.8)的更多相关文章

  1. ArrayList源码阅读笔记(基于JDk1.8)

    关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Obj ...

  2. ArrayList源码阅读笔记

    ArrayList ArrayList继承自AbstractList抽象类,实现了RandomAccess, Cloneable, java.io.Serializable接口,其中RandomAcc ...

  3. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  4. CopyOnWriteArrayList源码阅读笔记

    简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...

  5. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  6. HashMap源码阅读笔记

    HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述   HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...

  7. java8 ArrayList源码阅读

    转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...

  8. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  9. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

随机推荐

  1. HDD ,SSD和PCIE SSD性能测试

      PCIE SSD   * MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s] * KB = 1000 bytes, KiB = 10 ...

  2. Linux主机之间ssh免密登录配置方法

    由于公司的生产环境有很多台Linux的CentOS服务器, 为了方便机子(假设两台机子A,B)互相之间免密ssh, scp命令操作,配置如下 1. 在A.B上分别创建本机的公钥和私钥,输入命令后连续三 ...

  3. MySQL保留字 ERROR 1064 (42000)

    在MySQL(5.7.18)数据库中建表 CREATE TABLE SA_ACT_ITEM ( ITEMID ) NOT NULL, REGION ), ACTIONID ), ITEMNAME ), ...

  4. C#保存日志文件到txt中,可追加保存,定时删除最后一次操作半年前日志文件

    /// <summary> /// 输出指定信息到文本文件 /// </summary> /// <param name="msg">输出信息& ...

  5. Django中上传图片---避免因图片重名导致被覆盖

    上一篇文章中(https://www.cnblogs.com/lutt/p/10640412.html),我们以图片文件夹+图片名字的方式来储存图片,这样的做法会导致有重名的图片会导致之前的图片被覆盖 ...

  6. MAVEN简介之——pom.xml

    maven构建的生命周期 maven是围绕着构建生命周期这个核心概念为基础的.maven里有3个内嵌的构建生命周期,default,clean和site. default是处理你项目部署的:clean ...

  7. set nocount on/off的作用,可配合存储过程使用

    当set nocount 为NO的时候,不返回计数(受Transact-SQL语句影响行数) 当set nocount 为OFF时,返回计数(默认返回) 当 SET NOCOUNT 为 ON 时,将不 ...

  8. window注册鼠标右键菜单,及子菜单

    最近项目中要用到c#并且要注册鼠标点击右键菜单,在这里总结了几种方法以便记录 效果图: 1,reg注册,创建.reg文件,内容如下 Windows Registry Editor Version 5. ...

  9. POJ滑雪

    滑雪 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 97172   Accepted: 36843 Description ...

  10. spring mvc get请求中文乱码问题

    使用Spring MVC进行get请求时发现get请求带上中文参数,后台收到的是乱码,即使加了encoding filter也没用. 原因是,encoding filter 是针对post请求的,to ...