java基础之集合长度可变的实现原理
首先我们要明白java中的集合Collection,List,ArrayList之间的关系:
ArrayList是具体的实现类,实现了List接口
List是接口,继承了Collection接口
List继承了Collection接口 但是List是可以重复的并且有序的集合 Collection是不可重复且无序的
这里我们先讲一下List集合:
List接口不能被构造 也就是我们说的不能创建实例对象 但是我们可以像下面那样为List接口创建一个指向自己的对象引用 而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用 这也是多态的一种:
List<String> list = new ArrayList<String>();
那么现在问题来了
为什么要用 List list = new ArrayList() 而不用 ArrayList alist = new ArrayList()呢?
问题就在于List接口有多个实现类 现在你用的是ArrayList 也许哪一天你需要换成其它的实现类 如 LinkedList或者Vector等等 这时你只要改变这一行就行了:
List list = new LinkedList(); 其它使用了list地方的代码根本不需要改动
假设你开始用ArrayList alist = new ArrayList() 那需要改的地方就很多了 特别是如果你使用了ArrayList实现类特有的方法和属性。
这样的好处也是为了代码的可维护性 可复用性 可扩展性以及灵活性 再者就是这符合了里氏代换原则和开闭原则
言归正传 我们下面说一下 集合的长度为什么是不固定的
我们知道集合的底层其实也是用数组实现的 那么为什么定义集合的时候 是不需要给出size的 而数组在定义的时候就需要给出长度?
首先我们分析一下ArrayList的无参构造方法:
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
} /**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10; /**
* Shared empty array instance used for empty instances.
*/
private static final Object[] 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 == EMPTY_ELEMENTDATA will be expanded to
* DEFAULT_CAPACITY when the first element is added.
*/
private transient Object[] elementData;
我们发现无参的构造方法里面 this.elementData = EMPTY_ELEMENTDATA; 相当于给集合了一个空的数组 而且上面代码紫色部分说在第一次给集合添加元素的时候 会把 DEFAULT_CAPACITY 也就是10设置成数组长度
那么我们通过ArrayList中的add方法看一看是否是这样子:
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size; /**
* 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) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} private void ensureCapacityInternal(int minCapacity) {
//这里elementData==EMPTY_ELEMENTDATA 也就是上面无参构造方法里的的赋值, 所以这里的判断可以理解为是否是第一次添加元素时调用此方法
if (elementData == EMPTY_ELEMENTDATA) {
//如果是第一次添加元素 minCapacity应该为0+1 所以这里把DEFAULT_CAPACITY也就是10赋值给minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
//这里判断新添加一个元素以后 长度是否大于当前数组 如果大于则给数组扩容
//如果是第一次添加元素 肯定是true 然后把10传到grow方法中去
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 code
int oldCapacity = elementData.length;
//这里是给扩容后的数组定义的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果是第一次添加元素 new肯定是小于min的 所以把10赋给newCapacity 用来创建长度为10的新数组
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:
//把原来的数组copy到新数组中 如果是第一次add 则创建了一个长度为10的数组
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;
}
通过上面的代码 我们可以发现:
在第一次给集合添加元素的时候 的确会通过add方法及方法内调用的其他方法 创建一个长度为10的数组
并且以后每次add的时候 都会先判断一下 size+1是否超过了数组的长度 如果超过了长度就重新定义一个长度 int newCapacity = oldCapacity + (oldCapacity >> 1);的数组 然后把旧数组复制到新创建的数组中返回
解释一下 int newCapacity = oldCapacity + (oldCapacity >> 1); (oldCapacity >> 1)的意思是oldCapacity转换成2进制然后右移一位 也就是oldCapacity /2
综上所述 第一次给集合添加元素的时候 集合中数组的长度会被设置成10 每次数组元素满了以后 重新给数组设置的长度为 原数组长度+(原数组长度/2) (这里跟C#不同,C#中是初始长度为4 新数组长度=原数组长度*2)
java基础之集合长度可变的实现原理的更多相关文章
- Java基础之 集合体系结构(Collection、List、ArrayList、LinkedList、Vector)
Java基础之 集合体系结构详细笔记(Collection.List.ArrayList.LinkedList.Vector) 集合是JavaSE的重要组成部分,其与数据结构的知识密切相联,集合体系就 ...
- java基础-Map集合
java基础-Map集合 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Map集合概述 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它 ...
- 第6节:Java基础 - 三大集合(上)
第6节:Java基础 - 三大集合(上) 本小节是Java基础篇章的第四小节,主要介绍Java中的常用集合知识点,涉及到的内容包括Java中的三大集合的引出,以及HashMap,Hashtable和C ...
- 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!
前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...
- java基础技术集合面试【笔记】
java基础技术集合面试[笔记] Hashmap: 基于哈希表的 Map 接口的实现,此实现提供所有可选的映射操作,并允许使用 null 值和 null 键(除了不同步和允许使用 null 之外,Ha ...
- Java基础知识--集合
集合类 数组和集合的比较:数组可以存储对象,也可以存储基本数据类型,但是缺点就是长度固定,不能改变:集合长度是可变的,但是集合只能存储对象,集合可以存储不同类型的对象. Java容器类库一共有两种主要 ...
- 《回炉重造 Java 基础》——集合(容器)
整体框架 绿色代表接口/抽象类:蓝色代表类. 主要由两大接口组成,一个是「Collection」接口,另一个是「Map」接口. 前言 以前刚开始学习「集合」的时候,由于没有好好预习,也没有学好基础知识 ...
- 黑马程序员——【Java基础】——集合框架
---------- android培训.java培训.期待与您交流! ---------- 一.集合框架概述 (一)集合框架中集合类关系简化图 (二)为什么出现集合类? 面向对象语言对事物的体现都是 ...
- Java基础--说集合框架
版权所有,转载注明出处. 1,Java中,集合是什么?为什么会出现? 根据数学的定义,集合是一个元素或多个元素的构成,即集合一个装有元素的容器. Java中已经有数组这一装有元素的容器,为什么还要新建 ...
随机推荐
- <tf-idf + 余弦相似度> 计算文章的相似度
背景知识: (1)tf-idf 按照词TF-IDF值来衡量该词在该文档中的重要性的指导思想:如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性,正是我们所需要的关键词. ...
- (九)java位运算符
位运算符 &(与),|(或),^(异或),~(取反),<<(左移),>>(右移),>>>(无符号右移) 1:为true,0为false ...
- 深入了解ZooKeeper(一)
在上篇博客ZooKeeper初探之安装和配置中已经对Zookeeper这个“服务协调者”有了初步的认识和了解,一个字“美”,接下来开始深入的交往,开始了解其内心世界! 1. 内容思维导图 2. 分布式 ...
- NOIP2013DAY1题解
T1转圈游戏 十月のsecret 题解:快速幂 代码: #include<iostream> #include<cstring> #include<cstdio> ...
- Django工程目录结构优化
1.我看到这篇文章,写的不错,在此复制了一份,防止以后找不到! 感谢作者的翻译--->原文的链接:http://www.loonapp.com/blog/11/ 如果原文存在,请打开原文件阅读 ...
- FastAdmin 增删改查在哪里?
FastAdmin 增删改查在哪里? 一键生成 CRUD think crud -t test -u 1 执行命令合会在 controller 下生成 Test.php 控制器. 但是这个文件里确看不 ...
- 浅谈对【OSI七层协议】的理解
我们每天都在上网冲浪,在这背后到底有那些设备.协议去支撑呢?ISO是[Open System Interconnection]的缩写,该模型定义了不同计算机互联的标准,是设计和描述计算机网络通信的基本 ...
- 题目1539:师弟 ——最短路+DFS
题意::从起点到终点的所有的最短路中,找出离终点有X个路口的城市一共有几个 开始我用最短路+DFS从起点开始搜,超时了 换了一种方法,从终点开始搜,AC #include<stdio.h> ...
- UDP协议相关解释
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层 ...
- thinkphp中的session的使用和理解!
session的作用:session可以长时间的保存数据,不丢失. session的常用于: 1.登录,保存登录信息 2.保存购物车信息 3.保存验证码信息 定义session常量 define('W ...