java 数组长度 可变_java基础之集合长度可变的实现原理

首先我们要明白java中的集合Collection,List,ArrayList之间的关系:

ArrayList是具体的实现类,实现了List接口

List是接口,继承了Collection接口

List继承了Collection接口   但是List是可以重复的并且有序的集合 Collection是不可重复且无序的

这里我们先讲一下List集合:

List接口不能被构造 也就是我们说的不能创建实例对象 但是我们可以像下面那样为List接口创建一个指向自己的对象引用 而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用 这也是多态的一种:

List list = new ArrayList();

那么现在问题来了

为什么要用 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.*/

publicArrayList() {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 intsize;/*** Appends the specified element to the end of this list.

*

*@parame element to be appended to this list

*@returntrue (as specified by {@linkCollection#add})*/

public booleanadd(E e) {

ensureCapacityInternal(size+ 1); //Increments modCount!!

elementData[size++] =e;return true;

}private void ensureCapacityInternal(intminCapacity) {

//这里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(intminCapacity) {

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.

*

*@paramminCapacity the desired minimum capacity*/

private void grow(intminCapacity) {//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(intminCapacity) {if (minCapacity < 0) //overflow

throw newOutOfMemoryError();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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296339.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

与毒”共舞30年!清华美女研究生为何放弃高薪,选择特招入伍?背后的原因令人泪崩......

全世界只有3.14 % 的人关注了爆炸吧知识从武汉新冠疫情爆发到如今&#xff0c;陈薇没有一天休息。短短半年间&#xff0c;54岁的她头发从黑到白&#xff0c;也哭了好几次。刚去武汉-现在陈薇的母亲也在电视上看到了女儿的变化&#xff1a;“她变老了&#xff0c;都有白头发了。…

Windows7 IIS7.5 HTTP Error 503 The service is unavailable 另类解决方案

这篇文章是在你看了别的解决方案仍然解决不了之后才有用。 所以再未用别的解决方案之前&#xff0c;用了该解决方案依然无效的话&#xff0c;请自己看着办。 原创&#xff1a; .net2.0和.net3.5的应用程序池请在开始菜单打开VS2005或者VS2008的目录下的Visual Studio Tools文件…

总是想得太简单?试试我的方法

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「213」篇原创敬上大家好&#xff0c;我是Z哥。你是不是有时候遇到一些问题&#xff0c;脑子会很蒙&#xff0c;没有任何头绪&#xff1f;但是觉得身边的那些高手们…

Centos-启动network报错RTNETLINK answers: File exists解决方法

背景&#xff1a;今天在Vcenter上&#xff0c;用模板克隆了一个虚拟机&#xff0c;启动之后&#xff0c;网卡启动不了&#xff0c;报错如下&#xff1a;RTNETLINK answers: File exists说明&#xff1a; 环境 Centos6.6_X64 &#xff1b; 网卡两个原因&#xff1a; 由于用模板…

《信息存储与管理》读书笔记7 存储虚拟化

1、内存虚拟化 2、网络虚拟化 3、服务器虚拟化 4、存储虚拟化 1&#xff09;块级存储虚拟化 2&#xff09;文件级虚拟化 PS&#xff1a;详细内容请看虚拟化一板块转载于:https://blog.51cto.com/nppstudy/725855

java ready_Java PushbackReader ready()用法及代码示例

Java中的PushbackReader类的ready()方法用于检查此PushbackReader是否准备就绪。它返回一个布尔值&#xff0c;该值指示阅读器是否准备就绪。用法:public void ready()参数&#xff1a;此方法不接受任何参数返回值&#xff1a;此方法返回一个布尔值&#xff0c;该值指示此Pushb…

php Collection类的设计

用。net开发已经很多年了&#xff0c;最近接触到php&#xff0c;发现php也很好玩。不过发现它里面没有集合Collection类&#xff0c;只有数组&#xff0c;并且数组很强。这里我用数组来包装成一个集合Collection&#xff0c;代码如下&#xff1a; class Collection{private $_m…

不当败家子的原因......

1 实在是太真实&#xff01;▼2 有钱就是可以为所欲为&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 在哪都要有仪式感&#xff01;▼4 送自己去孤儿院......▼5 万万没想到...&#xff08;图源网络&#xff0c;侵删&#xff09;▼6 这都能催的&#xff1f;▼…

如何将 Linq 的查询结果转为 HashSet ?

咨询区 Jamie&#xff1a;我的类中有一个 ISet 类型的属性&#xff0c;我想将 linq 查询的结果赋给它&#xff0c;因为是 ISet 类型&#xff0c;所以我不知道是否有高效的方法将 linq 查询结果给之&#xff1f;简单来说&#xff0c;就像下面这样&#xff1a;ISet<T> foo …

ecs使用脚本安装oracle

ECS最低配置&#xff1a;CPU: 2核 内存&#xff1a;2G 数据盘&#xff1a;20G安装脚本分为 oracle11g 4个小版本&#xff0c;下载地址&#xff1a; http://zy-res.oss-cn-hangzhou-internal.aliyuncs.com/oracle/oracle11201.shhttp://zy-res.oss-cn-hangzhou-internal.aliyun…

我不信奉Scrum,我信奉敏捷

Scrum一直以来争论不断。虽然创始人Ken在演讲中曾说过即使是白痴也可以用Scrum&#xff0c;但是依然有很多人认为Scrum对团队成员的素质要求非常高。另据统计&#xff0c;75%以上的Scrum都可以称得上失败。 去年十月&#xff0c;有幸参加了Outsofting鲍央舟老师的Scrum培训。培…

仿京东商城源码java_Java+SSM实现类似京东的3C电子商城系统

需求分析基于Spring, SpringMVC, Mybatis 实现一个类似仿京东商城的3C电子商城系统, 能够实现商品管理与展示, 加入购物车, 支付购买等功能, 项目采用java技术进行开发。运行环境java, jdk1.8,tomcat8.5,mysql5.6,EclispseEE项目技术java, spring springmvc, mybatis, bootstra…

跨浏览器开发:CSS代码的金科玉律

作为Web设计师&#xff0c;你的网站在各种浏览器中有完全一样的表现是很多人的目标&#xff0c;然而这是一个永远无法真正实现的目标&#xff0c;很多人认为&#xff0c;完美的跨浏览器兼容并不必要&#xff0c;这样说虽然没错&#xff0c;但在很多情形&#xff0c;一种近似的兼…

Refit结合Polly访问ASP.NET Core Web API

前言在.NET Core应用中访问ASP.NET Core Web API接口&#xff0c;常用的方式是使用IHttpClientFactory生成HttpClient实例&#xff0c;并通过结合Polly策略&#xff0c;以实现重试&#xff0c;熔断等机制。在本文中&#xff0c;我们将介绍如何使用Refit&#xff0c;结合Polly访…

10个经典的爆炸化学反应,个个都是你惹不起的“暴脾气”

全世界只有3.14 % 的人关注了爆炸吧知识没有放过火&#xff0c;没有爆炸过&#xff0c;就不算真正学化学的。还有谁能比化学狗们的胆子更大、回忆更深刻吗&#xff1f;化学狗们能活到现在简直是个奇迹&#xff5e;&#xff5e;&#xff5e;懂的就默默转了吧&#xff01;小编整理…

根目录下各文件夹的作用

"/"目录下有好多文件&#xff0c;究竟有什么作用&#xff1f;整理综合了网上的一些资料&#xff0c;以RHEL6为标准。 一、管理类文件夹&#xff1a; /boot&#xff1a;包括内核和其它系统启动时使用的文件。 /initrd&#xff08;RHEL6中没有&#xff09;&#xff1a;…

java result元素_Java JDBC 中获取 ResultSet 的大小

当我们执行完一条Sql语句&#xff0c;获取到一个 ResultSet 对象后&#xff0c;有时我们需要立即知道到底返回了多少个元素&#xff0c;但是 ResultSet 并没有提供一个 size() 方法 or length 的属性&#xff0c;我们可以一个一个调用 next() 去累加计算&#xff0c;但是我们还…

wpf中的datagrid中如何显示图片

2012-09-11 10:55 在datagrid中添加一个模板列&#xff0c;xaml内容如下&#xff1a; <DataGridTemplateColumn Header"头像" Width"SizeToCells" IsReadOnly"True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> &…

狗为什么吃屎?真相男默女泪,但看完后你也会流口水......

全世界只有3.14 % 的人关注了爆炸吧知识别人笑狗太疯癫狗笑他人看不穿据说&#xff0c;200%的网友在学习一门新语言时&#xff0c;都会从最基本的日常问候语开始学起&#xff0c;例如——骂人。危险动作&#xff0c;请勿模仿。那但凡是学过汉语的人应该都知道&#xff0c;咱们中…

linux limit

linux ulimit调优 2010-05-21 23:54:39| 分类&#xff1a; linux | 标签&#xff1a; |字号大中小 订阅 1,说明:ulimit用于shell启动进程所占用的资源.2,类别:shell内建命令3,语法格式:ulimit [-acdfHlmnpsStvw] [size]4,参数介绍:-H 设置硬件资源限制.-S 设置软件资源限制.-a …