J2SE知识点摘记(二十一)
实现原理
前面已经提了一下Collection的实现基础都是基于数组的。下面我们就已ArrayList 为例,简单分析一下ArrayList 列表的实现方式。首先,先看下它的构造函数。
下列表格是在SUN提供的API中的描述:
ArrayList() Constructs an empty list with an initial capacity of ten. |
ArrayList(Collection c) Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator. |
ArrayList(int initialCapacity) Constructs an empty list with the specified initial capacity. |
其中第一个构造函数ArrayList()和第二构造函数ArrayList(Collection c) 是按照Collection 接口文档所述,所应该提供两个构造函数,一个无参数,一个接受另一个 Collection。
第3个构造函数:
ArrayList(int initialCapacity) 是ArrayList实现的比较重要的构造函数,虽然,我们不常用它,但是某认的构造函数正是调用的该带参数:initialCapacity 的构造函数来实现的。 其中参数:initialCapacity 表示我们构造的这个ArrayList列表的初始化容量是多大。如果调用默认的构造函数,则表示默认调用该参数为initialCapacity =10 的方式,来进行构建一个ArrayList列表对象。
为了更好的理解这个initialCapacity 参数的概念,我们先看看ArrayList在Sun 提供的源码中的实现方式。先看一下它的属性有哪些:
ArrayList 继承了AbstractList 我们主要看看ArrayList中的属性就可以了。
ArrayList中主要包含2个属性:
private transient Object elementData[];
private int size;
其中数组::elementData[] 是列表的实现核心属性:数组。 我们使用该数组来进行存放集合中的数据。而我们的初始化参数就是该数组构建时候的长度,即该数组的length属性就是initialCapacity 参数。
Keys:transient 表示被修饰的属性不是对象持久状态的一部分,不会自动的序列化。
第2个属性:size表示列表中真实数据的存放个数。
我们再来看一下ArrayList的构造函数,加深一下ArrayList是基于数组的理解。
从源码中可以看到默认的构造函数调用的就是带参数的构造函数:
public ArrayList(int initialCapacity)
不过参数initialCapacity=10 。
我们主要看ArrayList(int initialCapacity) 这个构造函数。可以看到:
this.elementData = new Object[initialCapacity];
我们就是使用的initialCapacity 这个参数来创建一个Object数组。而我们所有的往该集合对象中存放的数据,就是存放到了这个Object数组中去了。
我们在看看另外一个构造函数的源码:
这里,我们先看size() 方法的实现形式。它的作用即是返回size属性值的大小。然后我们再看另外一个构造函数public ArrayList(Collection c) ,该构造函数的作用是把另外一个容器对象中的元素存放到当前的List 对象中。
可以看到,首先,我们是通过调用另外一个容器对象C 的方法size()来设置当前的List对象的size属性的长度大小。
接下来,就是对elementData 数组进行初始化,初始化的大小为原先容器大小的1.1倍。最后,就是通过使用容器接口中的Object[] toArray(Object[] a) 方法来把当前容器中的对象都存放到新的数组elementData 中。这样就完成了一个ArrayList 的建立。
可能大家会存在一个问题,那就是,我们建立的这个ArrayList 是使用数组来实现的,但是数组的长度一旦被定下来,就不能改变了。而我们在给ArrayList对象中添加元素的时候,却没有长度限制。这个时候,ArrayList 中的elementData 属性就必须存在一个需要动态的扩充容量的机制。我们看下面的代码,它描述了这个扩充机制:
这个方法的作用就是用来判断当前的数组是否需要扩容,应该扩容多少。其中属性:modCount是继承自父类,它表示当前的对象对elementData数组进行了多少次扩容,清空,移除等操作。该属性相当于是一个对于当前List 对象的一个操作记录日志号。 我们主要看下面的代码实现:
1. 首先得到当前elementData 属性的长度oldCapacity。
2. 然后通过判断oldCapacity和minCapacity参数谁大来决定是否需要扩容
n 如果minCapacity大于oldCapacity,那么我们就对当前的List对象进行扩容。扩容的的策略为:取(oldCapacity * 3)/2 + 1和minCapacity之间更大的那个。然后使用数组拷贝的方法,把以前存放的数据转移到新的数组对象中
n 如果minCapacity不大于oldCapacity那么就不进行扩容。
下面我们看看上的那个ensureCapacity方法的是如何使用的:
上的两个add方法都是往List 中添加元素。每次在添加元素的时候,我们就需要判断一下,是否需要对于当前的数组进行扩容。
我们主要看看 public boolean add(Object o)方法,可以发现在添加一个元素到容器中的时候,首先我们会判断是否需要扩容。因为只增加一个元素,所以扩容的大小判断也就为当前的size+1来进行判断。然后,就把新添加的元素放到数组elementData中。
第二个方法public boolean addAll(Collection c)也是同样的原理。将新的元素放到elementData数组之后。同时改变当前List 对象的size属性。
类似的List 中的其他的方法也都是基于数组进行操作的。大家有兴趣可以看看源码中的更多的实现方式。
最后我们再看看如何判断在集合中是否已经存在某一个对象的:
由源码中我们可以看到,public boolean contains(Object elem)方法是通过调用public int indexOf(Object elem)方法来判断是否在集合中存在某个对象elem。我们看看indexOf方法的具体实现。
首先我们判断一下elem 对象是否为null ,如果为null的话,那么遍历数组elementData 把第一个出现null的位置返回。
如果elem不为null 的话,我们也是遍历数组elementData ,并通过调用elem对象的equals()方法来得到第一个相等的元素的位置。
这里我们可以发现,ArrayList中用来判断是否包含一个对象,调用的是各个对象自己实现的equals()方法。在前面的高级特性里面,我们可以知道:如果要判断一个类的一个实例对象是否等于另外一个对象,那么我们就需要自己覆写Object类的public boolean equals(Object obj) 方法。如果不覆写该方法的话,那么就会调用Object的equals()方法来进行判断。这就相当于比较两个对象的内存应用地址是否相等了。
在集合框架中,不仅仅是List,所有的集合类,如果需要判断里面是否存放了的某个对象,都是调用该对象的equals()方法来进行处理的。
J2SE知识点摘记(二十一)的更多相关文章
- J2SE知识点摘记(二)
1. 对象的声明 "类名 对象名 = new 类名();"例子:Person P;//先声明一个Person类的对象p p=new Person();//用new关键字实例化 ...
- J2SE知识点摘记(二十六)
为了用“集合框架”的额外部分把排序支持添加到 Java 2 SDK,版本 1.2,核心 Java 库作了许多更改.像 String 和 Integer 类如今实现 Comparable 接口以提供自然 ...
- J2SE知识点摘记(二十五)
Set 1.5.1 概述 Java 中的Set和正好和数学上直观的集(set)的概念是相同的.Set最大的特性就是不允许在其中存放的元素是重复的.根据这个特点,我们就可以使用Set 这个 ...
- J2SE知识点摘记(二十四)
覆写hashCode() 在明白了HashMap具有哪些功能,以及实现原理后,了解如何写一个hashCode()方法就更有意义了.当然,在HashMap中存取一个键值对涉及到的另外一个方法为equa ...
- J2SE知识点摘记(二十三)
我们简单介绍一下这个接口: 1.4.3 Comparable 接口 在 java.lang 包中,Comparable 接口适用于一个类有自然顺序的时候.假定对象集合是同一类型,该接口允 ...
- J2SE知识点摘记(二十二)
Map 1.4.1 概述 数学中的映射关系在Java中就是通过Map来实现的.它表示,里面存储的元素是一个对(pair),我们通过一个对象,可以在这个映射关系中找到另外一个和这个对象相关 ...
- J2SE知识点摘记(二十)
List 1.3.1 概述 前面我们讲述的Collection接口实际上并没有直接的实现类.而List是容器的一种,表示列表的意思.当我们不知道存储的数据有多少的情况,我们就可以使用Li ...
- J2SE知识点摘记-数据库(二)
一. 查询数据 注意sql的内容. 通过ResultSet接口保存全部的查询结果,通过Statement接口中的executeQuery()方法查询.查询之后需要分别取出.通过nex ...
- J2SE知识点摘记(十二)
1. File类 下面的构造方法可以用来生成File对象 File(String directoryPath) geName()用于返回文件名,getParent()返回父目录名,exist ...
随机推荐
- yum node.js
很久之前安装过windows下以及Mac下的node,感觉还是很方便的,不成想今天安装linux下的坑了老半天,特此记录. 首先去官网下载代码,这里一定要注意安装分两种,一种是Source Code源 ...
- discuz二次开发笔记(二)------跳转函数运用
前几天在增加修改功能时,突然用到一个提示函数,有点不理解,看了他的由来后果断做下笔记,感觉这在以后的开发中肯定还是要用的上的.有些地方不是很理解,在以后慢慢纠正.查补. Htm页面中用的js跳转: $ ...
- Android Studio 没有assets目录的问题
Where to place the assets folder in Android Studio If you are having problems with asset files not ...
- 一元云购qq互联回调地址错误解决办法
经过追踪,点击登录后调用 system/modules/api/下面的qqlogin.action.class.php 里面又调用了qq 互联php接口样例里的QC.php的QC类的方法qq_logi ...
- C语言函数qsort的使用方法
qsort函数stdlib.h文件中,函数原型为 void qsort(void *base,size_t nelem,size_t width,int (*Comp)(const void *,co ...
- SQL Server 文件流文件组
背景: 文件流通过在文件系统上存储blob数据文件将数据库引擎与ntfs文件集成在一起,使用t-sql和win32访问数据. 文件流使用windows系统来缓存数据,有助于在减少文件流数据对sql s ...
- 欧几里得求最大公约数--JAVA递归实现
欧几里得算法求最大公约数算法思想: 求p和q的最大公约数,如果q=0,最大公约数就是p:否则,p除以q余数为r,p和q的最大公约数即q和r的最大公约数. java实现代码: public class ...
- Ubuntu下Geary安装
sudo add-apt-repository ppa:yorba/ppasudo apt-get updatesudo apt-get install geary
- SNMP_802.1
http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a00801c9199.shtml http://www. ...
- centos6.4 ceph安装部署之cephFS
1,ceph fileSystem