首先我们要明白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基础之集合长度可变的实现原理的更多相关文章

  1. Java基础之 集合体系结构(Collection、List、ArrayList、LinkedList、Vector)

    Java基础之 集合体系结构详细笔记(Collection.List.ArrayList.LinkedList.Vector) 集合是JavaSE的重要组成部分,其与数据结构的知识密切相联,集合体系就 ...

  2. java基础-Map集合

    java基础-Map集合 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Map集合概述 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它 ...

  3. 第6节:Java基础 - 三大集合(上)

    第6节:Java基础 - 三大集合(上) 本小节是Java基础篇章的第四小节,主要介绍Java中的常用集合知识点,涉及到的内容包括Java中的三大集合的引出,以及HashMap,Hashtable和C ...

  4. 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!

    前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...

  5. java基础技术集合面试【笔记】

    java基础技术集合面试[笔记] Hashmap: 基于哈希表的 Map 接口的实现,此实现提供所有可选的映射操作,并允许使用 null 值和 null 键(除了不同步和允许使用 null 之外,Ha ...

  6. Java基础知识--集合

    集合类 数组和集合的比较:数组可以存储对象,也可以存储基本数据类型,但是缺点就是长度固定,不能改变:集合长度是可变的,但是集合只能存储对象,集合可以存储不同类型的对象. Java容器类库一共有两种主要 ...

  7. 《回炉重造 Java 基础》——集合(容器)

    整体框架 绿色代表接口/抽象类:蓝色代表类. 主要由两大接口组成,一个是「Collection」接口,另一个是「Map」接口. 前言 以前刚开始学习「集合」的时候,由于没有好好预习,也没有学好基础知识 ...

  8. 黑马程序员——【Java基础】——集合框架

    ---------- android培训.java培训.期待与您交流! ---------- 一.集合框架概述 (一)集合框架中集合类关系简化图 (二)为什么出现集合类? 面向对象语言对事物的体现都是 ...

  9. Java基础--说集合框架

    版权所有,转载注明出处. 1,Java中,集合是什么?为什么会出现? 根据数学的定义,集合是一个元素或多个元素的构成,即集合一个装有元素的容器. Java中已经有数组这一装有元素的容器,为什么还要新建 ...

随机推荐

  1. POSIX线程同步

    在posix编程中,如果在不同的线程中几乎同一时间操作同一个变量的时候,就会出现不同步. 如何解决这样的问题,这里需要用到互斥量,互斥锁的概念.请看UNIX环境高级编程P299页 #include & ...

  2. ng 双向数据绑定 实现 注册协议效果

    效果: 代码: <!DOCTYPE html> <html ng-app="myApp"> <head lang="en"> ...

  3. Go开发Struct转换成map两种方式比较

    最近做Go开发的时候接触到了一个新的orm第三方框架gorose,在使用的过程中,发现没有类似beego进行直接对struct结构进行操作的方法,有部分API是通过map进行数据库相关操作,那么就需要 ...

  4. Linux字符界面访问U盘

    首先查看U盘所在位置 fdisk -l 只需查看最后分区情况,例如找到U盘的位置为:/dev/sda1(视系统而定) 创建文件夹(用于挂载U盘内容) mkdir /mnt/usb 挂载 mount / ...

  5. 实现一个scnprinf

    #include <stdio.h> #include <stdarg.h> /* 该函数ret = min(size, 实际写入长度) - 1,即ret永远小于size * ...

  6. homebrew的安装与使用

    homebrew的安装:http://jingyan.baidu.com/article/fec7a1e5ec30341190b4e7e5.html 引用segfaultment上面的回答 没这个说法 ...

  7. maven help:system

    lifecycle:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html bindings:ht ...

  8. 我的HibernateSearch笔记

    话不多说,直接上代码: 实体类: package com.smt.pojo; import java.io.Serializable; import javax.persistence.Column; ...

  9. springboot redis简单结合

    参考: https://www.cnblogs.com/ityouknow/p/5748830.htmlhttp://blog.csdn.net/i_vic/article/details/53081 ...

  10. 使用YCSB测试mongodb

    项目里面需要对mongodb的性能进行测试,看了下网上很多做法都是使用YCSB进行测试,因此开始学习使用YCSB. 参考资料: YCSB github地址:https://github.com/bri ...