热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Java使用数组实现ArrayList的动态扩容的方法

这篇文章主要介绍了Java使用数组实现ArrayList的动态扩容的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

提到数组大家肯定不会陌生,但我们也知道数组有个缺点就是在创建时就确定了长度,之后就不能更改长度。所以Java官方向我们提供了ArrayList这个可变长的容器。其实ArrayList底层也是用数组进行实现的,今天我们就自己使用数组实现ArrayList的功能。

一、整体框架

废话不多说,我们以存放int类型元素为例,看一下ArrayList需要的成员变量和需要实现的方法。

public class ArrayList
 private int size;//用来记录实际存储元素个数
  private int[] elements;//用来存储元素的数组
  
  //构造方法:在创建ArrayList对象时,初始化elements数组
  public ArrayList(int capacity){
    elements = new int[capacity];
  }
 
 
 /**
 * 元素的数量
 * @return
 */
 public int size() {}
 /**
 * 是否为空
 * @return
 */
 public boolean isEmpty() {}
 /**
 * 查看元素的索引
 * @param element
 * @return
 */
 public int indexOf(int element) {}
 /**
 * 是否包含元素
 * @param element
 * @return
 */
 public boolean contains(int element) {}
 /**
 * 获取index位置的元素
 * @param index
 * @return
 */
 public int get(int index) {}
 /**
 * 设置index位置的元素
 * @param index
 * @param element
 * @return 原来的元素
 */
 public int set(int index, int element) {}
 /**
 * 在index索引位置插入元素
 * @param index
 * @param element
 */
 public void add(int index, int element) {}
 /**
 * 添加元素到尾部
 * @param element
 */
 public void add(int element) {}
 /**
 * 删除index位置的元素
 * @param index
 * @return
 */
 public int remove(int index) {}
 /**
 * 清除所有元素
 */
 public void clear() {}
 /**
 * 用来打印列表
 */
 public String toString() {}
  
}

二、方法实现

框架我们已经有了,接下来我们一步步实现方法就行。

size()方法:

这个方法很简单,因为我们有size属性,直接将其返回就行了。

public int size() {
 return size;
}

isEmpty()方法:

这个方法也很简单,判断是否为空只需要判断size是否为0即可。

public boolean isEmpty() {
 return size == 0;
}

indexOf(int element)方法:

这个方法是用来查询元素的所在索引位置,并返回。我们通过遍历列表查找即可,找到就将元素返回,没有找到返回-1。

public int indexOf(int element) {
  
 for (int i = 0; i 

contains(int element)方法:

这个方法是用来查看所传元素是否在数组中,我们可以直接通过indexOf()方法查看返回值是否不等于-1,不等于-1返回true,等于-1返回false。

public boolean contains(int element) {
 return indexOf(element) != -1;
}

get(int index)方法:

这个方法用来获取指定索引位置的元素,我们直接返回数组的指定索引位置元素即可。

public int get(int index) {;
 return elements[index];
}

set(int index, int element)方法:

这个方法用来将指定索引位置元素改为指定元素,并将原来元素返回,我们通过数组索引获取到该位置元素,并将指定元素赋值给该位置索引并将原来元素返回。

public int set(int index, int element) {
 int old = elements[index];
 elements[index] = element;
 return old;
}

add(int index, int element)方法:

个方法是在指定索引位置插入指定元素,我们首先将指定索引位置的元素以及之后所有的元素向后移动一位,然后再将指定元素赋值给数组的指定索引位置,最后并将size加1。

public void add(int index, int element) {

 for (int i = size; i > index; i--) {
 elements[i] = elements[i - 1];
 }
 elements[index] = element;
 size++;
 
}

add(int element)方法:

这个方法是在数组尾部添加元素,我们直接调用add(int index, int element)方法,将size作为index的参数传入即可。

public void add(int element) {
 add(size, element);
}

remove(int index)方法:

这个方法用来删除指定索引位置的元素,并将要删除元素返回,我们首先通过指定索引获取原来元素,当删除该元素后需要将index索引后面的所有元素向前移动一位,最后将size减1。

public int remove(int index) {
 int old = elements[index];
 for (int i = index + 1; i 

clear()方法:

这个方法,用于清空数组中所有元素,我们只需要将size赋值为0即可。

public void clear() {

 size = 0;
}

toString()方法:

这个方法用于将所有元素打印出来,通过StringBuilder对象进行拼接,最后转成字符串返回即可。

public String toString() {
 
 StringBuilder string = new StringBuilder();
 string.append("size=").append(size).append(", [");
 
 for (int i = 0; i 

以上代码基本实现了对数组的进行数据的增删改查,但最后想达到我们的目的还要进一步优化。

三、优化

1.实现动态扩容

当我们向数组中添加元素时,如果数组已经满了我们就需要就数组进行动态扩容。扩容的原理并不是真的对原数组进行增加内存操作,而是重新创建一个更大的数组,并将原数组的元素赋给新的数组。我们声明一个私有方法确保添加元素前数组的容量足够。

private void ensureCapacity(int capacity) {
 int oldCapacity = elements.length;
 if (oldCapacity >= capacity) return;
 
 // 新容量为旧容量的1.5倍
 int newCapacity = oldCapacity + (oldCapacity >> 1);
 int[] newElements = new int[newCapacity];
 for (int i = 0; i 

我们在add()方法中首先调用ensureCapacity(int capacity)方法进行判断数组容量是否足够,不够进行扩容。

public void add(int index, E element) {
 
 ensureCapacity(size + 1);
 
 for (int i = size; i > index; i--) {
 elements[i] = elements[i - 1];
 }
 elements[index] = element;
 size++;
}

2. 确保索引不越界

当我们在调用传入索引的方法时,首先要保证传入索引在可用范围内,不然会出现角标越界的异常。
定义outOfBound()方法,用于抛出角标越界异常信息。

private void outOfBounds(int index) {
 throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}

定义rangeCheck()方法用于检查索引是否越界,如果越界,调用outOfBound()抛出异常。

private void rangeCheck(int index) {
 if (index <0 || index >= size) {
 outOfBounds(index);
 }
}

而对于调用add()方法时所传入的索引范围可以取到size位置,我们在定义一个rangeCheckForAdd()方法,用于检查调用add()方法时索引是否越界。

private void rangeCheckForAdd(int index) {
 if (index <0 || index > size) {
 outOfBounds(index);
 }
}

在get()方法,set()方法和remove()方法中,先调用rangeCheck()方法,检查传入索引是否越界。

public int get(int index) {
 rangeCheck(index);
 return elements[index];
}

public int set(int index, E element) {
 rangeCheck(index);
 
 int old = elements[index];
 elements[index] = element;
 return old;
}

public int remove(int index) {
 rangeCheck(index);
 
 int old = elements[index];
 for (int i = index + 1; i 

3. 设置常量以及重写构造方法

对于类中的常数我们更希望封装成常量,并且声明一个默认容量,希望在创建对象时未传入容量参数或传入容量参数过小直接创建一个相对大小合适的数组。

private static final int DEFAULT_CAPACITY = 10;//我们将默认容量设为10
private static final int ELEMENT_NOT_FOUND = -1;//我们将获取指定元素的索引时,未找到的返回值-1封装为常量

//声明无参构造方法,在调用无参构造方法是直接创建默认容量的数组
public ArrayList(){
  elements = new int[DEFAULT_CAPACITY];
}

//声明有参构造方法,在传入参数小于默认容量时,我们仍然创建默认容量数组
public ArrayList(int capaticy) {
 capaticy = (capaticy 

四、使用泛型

以上步骤已经使用数组完全实现了ArrayList的全部功能,但只能存放int类型的数据,如果我们希望储存其他类型的数据我们只需要使用Java中的泛型就能够完成。

思路与上述完全一样,整体代码如下:

public class ArrayList {
 /**
 * 元素的数量
 */
 private int size;
 /**
 * 所有的元素
 */
 private E[] elements;
 
 private static final int DEFAULT_CAPACITY = 10;
 private static final int ELEMENT_NOT_FOUND = -1;
 
 public ArrayList() {
 elements = (E[]) new Object[DEFAULT_CAPACITY];
 }
 
 public ArrayList(int capaticy) {
 capaticy = (capaticy  index; i--) {
  elements[i] = elements[i - 1];
 }
 elements[index] = element;
 size++;
 }

 /**
 * 删除index位置的元素
 * @param index
 * @return
 */
 public E remove(int index) {
 rangeCheck(index);
 
 E old = elements[index];
 for (int i = index + 1; i = capacity) return;
 
 // 新容量为旧容量的1.5倍
 int newCapacity = oldCapacity + (oldCapacity >> 1);
 E[] newElements = (E[]) new Object[newCapacity];
 for (int i = 0; i = size) {
  outOfBounds(index);
 }
 }
 
 private void rangeCheckForAdd(int index) {
 if (index <0 || index > size) {
  outOfBounds(index);
 }
 }
 
 @Override
 public String toString() {
 StringBuilder string = new StringBuilder();
 string.append("size=").append(size).append(", [");
 for (int i = 0; i 

到此这篇关于Java使用数组实现ArrayList的动态扩容的方法的文章就介绍到这了,更多相关Java ArrayList动态扩容内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 题库来源:安全生产模拟考试一点通公众号小程序G3锅炉水处理报名考试是安全生产模拟考试一点通生成的,G3锅炉水处理证模拟考试题库是根据G3锅炉水处理最新 ... [详细]
  • 本文详细探讨了Netty中Future及其子类的设计与实现,包括其在并发编程中的作用和具体应用场景。我们将介绍Future的继承体系、关键方法的实现细节,并讨论如何通过监听器和回调机制来处理异步任务的结果。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本文探讨了在Linux系统上使用Docker时,通过volume将主机上的HTML5文件挂载到容器内部指定目录时遇到的403错误,并提供了解决方案和详细的操作步骤。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 作为一名专业的Web前端工程师,掌握HTML和CSS的命名规范是至关重要的。良好的命名习惯不仅有助于提高代码的可读性和维护性,还能促进团队协作。本文将详细介绍Web前端开发中常用的HTML和CSS命名规范,并提供实用的建议。 ... [详细]
  • 本文探讨了在 ASP.NET MVC 5 中实现松耦合组件的方法。通过分离关注点,应用程序的各个组件可以更加独立且易于维护和测试。文中详细介绍了依赖项注入(DI)及其在实现松耦合中的作用。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 自己用过的一些比较有用的css3新属性【HTML】
    web前端|html教程自己用过的一些比较用的css3新属性web前端-html教程css3刚推出不久,虽然大多数的css3属性在很多流行的浏览器中不支持,但我个人觉得还是要尽量开 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 科研单位信息系统中的DevOps实践与优化
    本文探讨了某科研单位通过引入云原生平台实现DevOps开发和运维一体化,显著提升了项目交付效率和产品质量。详细介绍了如何在实际项目中应用DevOps理念,解决了传统开发模式下的诸多痛点。 ... [详细]
author-avatar
被爱的小花花_
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有