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中已经有数组这一装有元素的容器,为什么还要新建 ...
随机推荐
- C 时间函数总结
头文件 time.h 处理器时间函数 clock_t clock(void) 处理器的处理时间,如可以在 main开始的地方 使用这个函数,然后再 完毕后 调用这个函数 并 减去 之前的返回值,为了 ...
- 解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题
解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题 解决 Laravel/Lumen 出现 "Pleas ...
- HTML服务器控件与Web服务器控件
asp.net之所以现在开发方便和快捷,关键是它有一组强大的控件库,包括web服务器控件,web用户控件,web自定义控件,html服务器控件和html控件等.这里主要整理一下html控件.html服 ...
- matlab中hdl coder 的使用
今天摸索了一下hdl coder的使用方法,各个步骤主要是照猫画虎,有些地方还是不理解,先总结一下: 1.要想调用quartus或者Xilinx综合布局布线需要先设置,设置的方法有两种,命令窗口输入 ...
- Hadoop体系结构之 HDFS
HDFS采用主从(Master/Slave)结构模型,一个HDFS集群是由一个NameNode和若干个DataNode组成的(在最新的Hadoop2.2版本已经实现多个NameNode的配置-这也是一 ...
- UCloud 云服务器硬盘扩容后 如何挂载到本机
UCloud 云服务器硬盘扩容后如何挂载到本机 UCloud 提供的云服务器会根据不同的系统初始化不同空间大小的硬盘资源,此资源默认为 系统盘. 针对 Linux 系统默认初始化 20G 的空间,一般 ...
- laravel 二维码生成器包 QrCode 的使用
在laravel中使用 QrCode 生成二维码 https://laravelacademy.org/post/2605.html 我在本机的windows下composer require 没有成 ...
- (转)oracle - type
本文转载自:http://www.cnblogs.com/o-andy-o/archive/2012/05/25/2517741.html type定义: oracle中自定义数据类型oracle中有 ...
- Java-Runoob-高级教程:Java MySQL 连接
ylbtech-Java-Runoob-高级教程:Java MySQL 连接 1.返回顶部 1. Java MySQL 连接 本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL ...
- win7 网站发布备注
1.更改 .NET Framework 版本(改原设置v2.0 为v4.0) 2.程序池设置 3.基本设置 4.Web.config (debug="false") <sys ...