java集合实现--02 --源代码学习--集合增加对象原理

其实上次我们已经看了ArrayList对象创建后产生的一些现象,下面我们通过源码在来看看往ArrayList集合里面操作对象都有什么现象:

1、增加一个对象,首先看下源代码:

/** * 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}) */ public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! 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) { if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }

2、我们可以看出它其实是有两个增加对象的方法,一个就是直接增加,另外一个就是指定位置直接增加,其实他们两个是有很大的不同

。好,那么我们先看看他直接增加的时候是什么样的一个过程:

a) 我们看见增加的第一部里面有个 //Increments 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. * * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } }

从这个地方的源代码我们可以看出:其实它是判断增加对象后的 minCapacity 是否比之前容器的size(oldCapacity)大,如果大

的话就开始扩充容器,扩充容器的算法是 (size * 3 )/2 + 1, 它跟vector是不一样的扩容算法,vector是 size * 2,

接着我们可以看到。然后它又检查了一次,然后通过数组的静态工具类Arrays的copyOf方法来扩充了容器,最后返回增加方法:

elementData[size++] = e;

增加了一个对象,由上面我们还可以看出,其实如果ArrayList是按照正常的增加,即在后面增加对象,其实并没有涉及内容移动

只有在容器不够的时候扩充容器,并无很大的内容开销,换句话说其实它增加一个对象是开销是基本常量的时间。

b)现在我们来看看在ArrayList指定的位置增加一个对象,好,咱们看看它实现的源代码:

/** * 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) { if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }

从源代码上我们可以看出,它其实是先判断要增加的位置是否在容器的容量范围内,如果不在,则抛出了我们很熟悉的

异常 IndexOutBoundsException(); 恩~不错,下次如果你不小心捉到这样的异常可千万别说这是什么原因了咕~~(╯﹏╰)b

。好了,我们接着往下看,又看见我们刚刚说的扩容,这里就不在进去看了。接下来就是要在指定位置增加某个对象。

首先,它会用System.arraycopy() 方法把原来的对象从要指定增加的位置向后拷贝一个位置,比如:

现在又个集合有: 1,2,3,4,5 的5个对象,我们要在2位置上增加一个:a 其实它的实现方法是 把 3,4,5 往后面拷贝,这个时候数组

变成: 1,2,3,3,4,5 。然后我们在往下看它在往指定的位置把刚刚指定的对象放上去,这个时候就是:1,2,a,3,4,5可以看见它就是

我们想要的结果了。要了解到这个主要是要理解System.arraycopy();方法的使用则可以了解。我们也可以看见其实往ArrayList

里面指定的位置增加一个对象,如果我们增加的位置不是最后的位置,其实它也没有涉及内存的移动,花费时间跟正常增加一个对象

也是一样的。

其实在指定的位置增加对象还有个问题:比如你指定的位置刚刚好是现在的容易的size + 1的位置,我们是可以正常增加的

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

从这句代码我们可以看的出,然而如果你增加的位置超过size + 1是会有异常的,这个大家千万要注意了额。额外的说个问题,

很多人觉得很奇怪,为什么我们System.out.println()对象的时候只是打出个地址,而我们打印集合的时候则会看见里面的对

象,这个我们就要追溯到它们的抽象类了,我们会在AbstractCollection里面看见它重写了toString() 方法:

/** * Returns a string representation of this collection. The string * representation consists of a list of the collection's elements in the * order they are returned by its iterator, enclosed in square brackets * (<tt>"[]"</tt>). Adjacent elements are separated by the characters * <tt>", "</tt> (comma and space). Elements are converted to strings as * by {@link String#valueOf(Object)}. * * @return a string representation of this collection */ public String toString() { Iterator<E> i = iterator(); if (! i.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { E e = i.next(); sb.append(e == this ? "(this Collection)" : e); if (! i.hasNext()) return sb.append(']').toString(); sb.append(", "); } }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值