Java自定义一个变长数组的思路与代码
更新时间:2022年12月30日 14:05 点击:237 作者:余数kl
前言
首先需要声明的是,Java
本身是提供了变长数组的,即ArrayList
。那么自定义一个变长数组有啥用?其实没啥用或者说用处不大,主要就是为了了解下变长数组的设计理念而已。实际工作中直接使用ArrayList
。
思路分析
主要功能点:
- 新建时可以指定容量大小,不指定时使用默认容量大小。
- 向数组中追加新元素,当超过容量时应该自动扩容。
- 向数组中指定位置添加新元素,需要考虑指定的下标是否越界,同样也需要考虑扩容操作。
- 删除末尾的元素,需要考虑缩小容量。
- 删除指定位置元素,需要考虑指定的下标是否越界,同样也需要考虑缩小容量。
- 修改特定位置的元素,需要考虑指定的下标是否越界。
- 以时间复杂度为O ( 1 ) O(1)O(1)获取任意位置的元素,需要考虑指定的下标是否越界。
主要注意点:
- 扩容: 这里扩容2倍(ArrayList 是扩容 1.5 倍),扩容时新建一个2倍容量的新数组,然后将旧数组中的元素按顺序拷贝到新数组。
- 缩容: 当数组中的元素个数 <= 0.25 * 容量时,自动缩小容量为原来的一半,新建一个容量是原来容量一半的数组,然后将旧数组中的元素按顺序拷贝到新数组。(ArrayList缩小为和当前元素个数一样大)。
- 指定位置添加: 需要先将指定位置及后面所有的元素都向后移动一位,将指定位置空出来然后再插入。
- 指定位置删除: 先将制定位置删除,然后将后面的所有元素都向前移动一位。
- 容量大小: 需要指定容量的最大值,避免OOM的发生。最小值可以指定也可以不指定。
实现代码
/** * 变长数组 * */ public class ResizeableArray<E> { private static final int MIN_CAPACITY = 10; private static final int MAX_CAPACITY = Integer.MAX_VALUE - 8; // 当前实际数据大小 private int size = 0; // 实际存放元素的数组,容量为 elements.length private Object[] elements; public ResizeableArray(){ this(MIN_CAPACITY); } public ResizeableArray(int initCapacity){ if(initCapacity < MIN_CAPACITY){ initCapacity = MIN_CAPACITY; }else if(initCapacity > MAX_CAPACITY){ initCapacity = MAX_CAPACITY; } this.elements = new Object[initCapacity]; } // 数组的特性,根据下标获取元素 public E get(int index){ this.checkIndex(index); return (E)elements[index]; } // 添加一个元素到最后 public void add(E element){ if(size == elements.length){ // 需要扩容 this.expandCapacity(); } elements[size++] = element; } // 添加一个元素到指定位置 public void add(int index, E element){ if(index == size){ this.add(element); return; } this.checkIndex(index); if(size == elements.length){ // 需要扩容 this.expandCapacity(); } // 需要先将index和之后的所有元素向后移动一位 for(int i = size - 1; i >= index; i--){ elements[i + 1] = elements[i]; } elements[index] = element; size++; } // 设置下标为index的元素 private void set(int index, E element){ this.checkIndex(index); elements[index] = element; } /** * 删除下标为index的元素 * 当 size <= 0.25 * capacity 的时候缩小容量 */ private void delete(int index){ this.checkIndex(index); elements[index] = null; // 如果删除的不是最后一个元素,需要将后续元素往前移动一位 if(index < size - 1){ for(int i = index + 1; i < size; i++){ elements[i - 1] = elements[i]; } } size--; if(size <= 0.25 * elements.length){ this.reduceCapacity(); } } private void deleteLast(){ this.delete(size - 1); } private void checkIndex(int index){ if(index < 0 || index >= size){ throw new IndexOutOfBoundsException(String.format("Out of bounds at: %s, size is: %d", index, size)); } } private void expandCapacity(){ if(MAX_CAPACITY == elements.length){ // 容量达到最大限制,无法扩容。 throw new RuntimeException("The capacity has reached its maximum limit and cannot be expanded."); } int newCapacity = Math.min(elements.length << 1, MAX_CAPACITY); Object[] newElements = new Object[newCapacity]; System.arraycopy(elements, 0, newElements, 0, size); elements = newElements; } private void reduceCapacity(){ if(elements.length == MIN_CAPACITY){ return; } int newCapacity = Math.max(elements.length >> 1, MIN_CAPACITY); Object[] newElements = new Object[newCapacity]; System.arraycopy(elements, 0, newElements, 0, size); elements = newElements; } public static void main(String[] args){ ResizeableArray<Integer> resizeableArray = new ResizeableArray<>(); System.out.printf("初始化后,size为: %d \n", resizeableArray.size); System.out.printf("初始化后,capacity为: %d \n", resizeableArray.elements.length); System.out.println(); for(int i = 0; i < 20; i++){ resizeableArray.add(i); } System.out.printf("添加20个元素后,size为: %d \n", resizeableArray.size); System.out.printf("添加20个元素后,capacity为: %d \n", resizeableArray.elements.length); System.out.printf("添加20个元素后,第5个元素是: %d \n", resizeableArray.get(4)); System.out.println(); resizeableArray.delete(4); System.out.printf("删除第五个元素后,size为: %d \n", resizeableArray.size); System.out.printf("删除第五个元素后,capacity为: %d \n", resizeableArray.elements.length); System.out.printf("删除第五个元素后,第5个元素是: %d\n", resizeableArray.get(4)); System.out.println(); resizeableArray.add(4, 100); System.out.printf("在第五个位置插入元素后,size为: %d \n", resizeableArray.size); System.out.printf("在第五个位置插入元素后,capacity为: %d \n", resizeableArray.elements.length); System.out.printf("在第五个位置插入元素后,第5个元素是: %d\n", resizeableArray.get(4)); System.out.println(); for(int i = 0; i < 15; i++){ resizeableArray.deleteLast(); } System.out.printf("删除后面15个元素后,size为: %d \n", resizeableArray.size); System.out.printf("删除后面15个元素后,capacity为: %d \n", resizeableArray.elements.length); System.out.printf("删除后面15个元素后,第5个元素是: %d\n", resizeableArray.get(4)); System.out.println(); resizeableArray.set(4, 200); System.out.printf("修改第五个元素后,当前size为: %d \n", resizeableArray.size); System.out.printf("修改第五个元素后,capacity为: %d \n", resizeableArray.elements.length); System.out.printf("修改第五个元素后,第5个元素是: %d\n", resizeableArray.get(4)); } }
测试结果
由执行结果可知:
- 初始化后默认容量为
10
。 - 添加元素超过
10
个后会自动扩容。 - 删除一个元素后,
size
会减1
,后面元素会自动向前移动一位。 - 插入一个新元素后,
size
会加1
,后续元素后移一位。 - 删除到只有
0.25 * 容量
个元素后,会自动缩小容量。
总结
到此这篇关于Java自定义一个变长数组的思路与代码的文章就介绍到这了,更多相关Java自定义变长数组内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
原文出处:https://blog.csdn.net/justyuze/article/details/128477999
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 这篇文章主要给大家介绍了关于C#创建自定义控件及添加自定义属性和事件使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-06-25
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 本文实例讲述了JS实现自定义简单网页软键盘效果。分享给大家供大家参考,具体如下:这是一款自定义的简单点的网页软键盘,没有使用任何控件,仅是为了练习JavaScript编写水平,安全性方面没有过多考虑,有顾虑的可以不用,目的是学...2015-11-08
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
- 自定义一个jquery模态窗口插件,将它集成到现有平台框架中时,它只能在mainFrame窗口中显示,无法在顶层窗口显示. 解决这个问题的办法: 通过以下代码就可能实现在顶层窗口弹窗 复制代码 代码如下: $(window.top.documen...2014-05-31
- 这篇文章主要介绍了自定义feignClient的常见坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-20
- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03