在前面的几节里,本教程从整体架构上去把握了JDK中的集合框架,并简单分析了其中Collection组的顶级接口,知道Collection接口的常见直接子接口有List、Set和Queue,并就这三个子接口的独有特性进行了简单地分析和比较。

本篇教程将会对实际编程中使用最频繁、最简单地ArrayList进行讲解,我先给出一个该类的类层次结构图。

从上面的结构图可以看出,集合框架的主题架构其实是以类为主体的,而不是接口。如果知道类、抽象类和接口之间的区别与联系,就能明白这里引入抽象类的原因。简单地说,如果不引入抽象类,每个具有Collection接口属性的类别都必须自己去实现该接口中的10多个方法,通过让类别直接继承自AbstractCollection这个抽象类,去除了重复代码。

首先,我们来看一下AbstractCollection这个抽象类的部分源码,如下:

public abstract class AbstractCollection<E> implements Collection<E> {

public boolean isEmpty() {

return size() == 0;

}

public boolean add(E e) {

throw new UnsupportedOperationException();

}

}

此抽象类就是Collection接口的实现,并实际实现了其中的某些方法,而且作为一个抽象类是不能直接用来实例化对象。

其次,再看看AbstractList这个抽象类的部分源码,如下:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {

public boolean add(E e) {

add(size(), e);

return true;

}

}

此抽象类继承了AbstractCollection抽象类,并且实现了List接口,这就使得此类同时具备了普通Collection和特定的List类型集合的属性。注意:此类的subList方法返回的List<E>类型是两个内部类中的一个,要么是RandomAccessSubList<E>,要么是SubList<E>。

最后,我们再来仔细看看ArrayList的源码,部分源码如下:

public class ArrayList<E> extends AbstractList<E>

implements List<E>, RandomAccess, Cloneable, java.io.Serializable

{

private static final int DEFAULT_CAPACITY = 10;

private transient Object[] elementData;

}

这个ArrayList作为一个非抽象方法,已经实现了抽象父类和父接口中的所有方法。整体来说,并没有太多新的方法和特性加入,但其中值得关注的点不少,现在我们就来一一剖析。

第一个不寻常的地方在于ArrayList实现了Serializable接口,但是该类的重要成员elementData却使用transient修饰符。transient修饰符的作用正是让被其修饰的变量不参与正常的序列化中,那么ArrayList是如何实现Serializable的呢?秘密藏在该类的两个方法:

private void writeObject(java.io.ObjectOutputStream s)

throws java.io.IOException{

}

private void readObject(java.io.ObjectInputStream s)

throws java.io.IOException, ClassNotFoundException {

}

我们知道对于实现了Serializable接口的类,我们可以直接使用ObjectOutputStream和ObjectInputStream进行对象的序列化和反序列化。当我们的类中包含有这两个方法时,ObjectOutputStream的writeObject方法就会调用类中的writeObject方法。注意:如果的看得够仔细,你会发现writeObject方法是私有的,同时该方法在Object中并不存在,那么ObjectOutputStream作为外部类是如何找到writeObject方法并调用成功的呢?如果你知道Java的反射机制的话,我相信你可能已经猜到了,此处正是使用的反射机制。这里之所以如何操作是为了效率,毕竟只需要序列化elementData中size大小的变量,而不是capacity大小的变量。

第二个不寻常的地方在于ArrayList类的clone()方法,从类的定义中可以看到该类实现了Cloneable接口,根据Cloneable接口的语义,ArrayList类实现了自己的clone()方法,我们看一下源码:

public Object clone() {

try {

@SuppressWarnings("unchecked")

ArrayList<E> v = (ArrayList<E>) super.clone();

v.elementData = Arrays.copyOf(elementData, size);

v.modCount = 0;

return v;

} catch (CloneNotSupportedException e) {

// this shouldn't happen, since we are Cloneable

throw new InternalError();

}

}

源码面前无秘密,可以看到方法中对于保存ArrayList内部数据的数组变量elementData是做了复制的,但是并没有针对数组变量本身再进行递归复制,所以在注释中写明了此方法是一个浅复制。

第三个不寻常的地方在于ArrayList类中含有一个名为modCount的变量,名字其实是modifyCount的缩写,表示ArrayList对象被修改的次数。而且这个modCount记录的只是修改size变量的次数,对于ArrayList对象中变量的替换是不会改变modCount的值。那么ArrayList类为什么要辛苦地去维护这个modCount变量值呢?如果你写过遍历ArrayList集合的同时去删除集合中某些元素的代码,并且你不是使用的迭代器方式的话,那么你一定遇到过ConcurrentModificationException异常。背后的原理就在于remove方法会修改modCount的值,而整个foreach循环过程不允许modCount值发生改变。

第四点来看一下ArrayList的内存数组增长机制,ArrayList模拟可动态增长的数组,其采用的内存增长机制也是很多笔试和面试题喜欢设计的话题,我们直接来看一下源码:

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

}

从源码可以出到,通常情况下就是一个50%的增长幅度,但也可以直接设定具体增长的目标值。同时,某些JVM实际可分配的最大数组大小并不能达到Integer.MAX_VALUE,而是Integer.MAX_VALUE - 8。

关于ArrayList<E>还有比较多的知识点,限于篇幅就不一一讲解了,像其中迭代器模式的实现,内部类的使用等就暂时先跳过啦,以后以机会再专门讲解。最后提一下ArrayList<E>实现的RandomAccess这个接口,它是一个标记接口,本身不包含任何成员,用来标记某些集合类具有随机访问性,从而在应用泛型算法可以考虑利用该特点来提高算法性能。

本系列文档会在本人的微信公众号发布,欢迎大家扫码关注。

                

008 Java集合浅析3的更多相关文章

  1. 009 Java集合浅析4

    前面一篇教程中,我们分析了List派别中的最常见也最重要的一个类ArrayList<E>.从我们的分析来看,ArrayList作为动态数组的模拟,使用的是连续内存空间来存储数据,带来了可随 ...

  2. Java集合框架之TreeMap浅析

    Java集合框架之TreeMap浅析 一.TreeMap综述: TreeMap在Map中的结构如下:

  3. Java集合框架之HashMap浅析

    Java集合框架之HashMap浅析 一.HashMap综述: 1.1.HashMap概述 位于java.util包下的HashMap是Java集合框架的重要成员,它在jdk1.8中定义如下: pub ...

  4. Java集合框架之Map接口浅析

    Java集合框架之Map接口浅析 一.Map接口综述: 1.1java.util.Map<k, v>简介 位于java.util包下的Map接口,是Java集合框架的重要成员,它是和Col ...

  5. Java集合框架之TreeSet浅析

    Java集合框架之TreeSet浅析 一.TreeSet综述: 1.1TreeSet简介: TreeSet是Java集合框架的重要成员,先来看看TreeSet在jdk1.8中的定义吧: public ...

  6. Java集合框架之HashSet浅析

    Java集合框架之HashSet浅析 一.HashSet综述: 1.1HashSet简介 位于java.util包下的HashSet是Java集合框架的重要成员,它在jdk1.8中定义如下: publ ...

  7. Java集合框架之Set接口浅析

    Java集合框架之Set接口浅析 一.java.util.Set接口综述: 这里只对Set接口做一简单综述,其具体实现类的分析,朋友们可关注我后续的博文 1.1Set接口简介 java.util.se ...

  8. Java集合框架之Vector浅析

    Java集合框架之Vector浅析 一.Vector概述: 位于java.util包下的Vector是Java集合框架的重要一员,虽然没有ArrayList那么的常用,但是我们还要对其做相关学习: 1 ...

  9. Java集合框架之LinkedList浅析

    Java集合框架之LinkedList浅析 一.LinkedList综述: 1.1LinkedList简介 同ArrayList一样,位于java.util包下的LinkedList是Java集合框架 ...

随机推荐

  1. leetcode难度及面试频率

    转载自:LeetCode Question Difficulty Distribution                 1 Two Sum 2 5 array sort           set ...

  2. win8 64位+Oracle 11g 64位下使用PL/SQL Developer 的解决办法

    1)安装Oracle 11g 64位2)安装32位的Oracle客户端( instantclient-basic-win32-11.2.0.1.0)下载 instantclient-basic-win ...

  3. UED大全

    http://www.baiduux.com/  百度UFOhttp://ued.sohu.com/  搜狐UEDhttp://ued.taobao.com/  淘宝UEDhttp://www.ued ...

  4. Bootstrap入门(十四)组件8:媒体对象

    Bootstrap入门(十四)组件8:媒体对象 这是一个抽象的样式,用以构建不同类型的组件,这些组件都具有在文本内容的左或右侧对齐的图片(就像博客评论或 Twitter 消息等). 1.基本样式 2. ...

  5. TCP协议滑动窗口(一)——控制数据传输速率

    窗口大小:TCP头中一个16位的域,表示当前可用接受缓冲区大小.在每个TCP对等段连接初始化时,告诉对方自己的窗口大小(不一定是满额,假如满额65201字节,可能暂时通告5840字节).若客户端接受数 ...

  6. 多线程方式实现Socket通信

    一.首先,介绍下两类传输协议:TCP:UDP TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议.通过TCP协议传输,得到的是一个顺序的无差错的数据流 ...

  7. 使用net Manager工具远程连接oracle

    一,在服务端配置oracle端口 在命令行中输入netca命令,打开相关配置默认端口号为1521 二,配置端口后使用Telnet工具调试端口是否联通 在命令行输入telnet 服务器ip 端口号 三, ...

  8. Vue.js 系列教程 ②

    这是关于 JavaScript 框架 Vue.js 五个教程的第二部分.在这一部分,我们将学习组件,Props 以及 Slots.这不是一个完整的指南,而是基础知识的概述,所以你可以了解Vue.js ...

  9. UI进阶 即时通讯之XMPP登录、注册

    1.XMPP环境搭建 http://www.cnblogs.com/fearlessyyp/p/5506644.html 第一次打开可能会有点儿慢,图片很多,步骤很详细,祝搭建成功. 2.工程中添加X ...

  10. Jasmine基础语法

    简介 Jasmine 是JavaScript的测试框架,它不依赖其他框架,也不依赖DOM,更重要的是它语法简单.以下实例都是基于Jasmine 2.5.2的,并且来自官网:https://jasmin ...