造轮子ArrayList
这篇博客实现一个简单的ArrayList集合.博客里的代码首先根据自己的想法实现,在走不动的情况下会去参考JDK源代码.所以阅读本文,不要抱着跟JDK源码对比的心态.于我个人而言,国庆期间,纯属娱乐.写完打游戏去.
首先写搭建一个架子
public class MyArrayList<E> {
/*
* 注意ArrayList的大小是可变的,此处设定的数组大小为默认大小,和每次扩建的大小
* */ //默认的数组大小
private int DEFAULT_CAPACITY = 1;
//存储元素的数组
private Object[] elements; //当前下标默认值
private int index = 0; //构造一个默认长度的集合
public MyArrayList() {
this.elements = new Object[DEFAULT_CAPACITY];
} //构造一个指定长度的集合.
public MyArrayList(int capacity) {
this.DEFAULT_CAPACITY = capacity;
this.elements = new Object[DEFAULT_CAPACITY];
} //添加元素
public boolean add(E e) {
//设置元素到指定下标位置
elements[index] = e;
//下标自增
index++;
return true;
} //返回当前集合长度
public int size(){
return index;
}
}
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList();
myArrayList.add(1);
System.out.println(myArrayList.size());//
}
}
我们再来尝试创建一个指定大小的集合.
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(0);
myArrayList.add(1);
System.out.println(myArrayList.size());
}
}
这时是会报错的,如果你指定了一个大小为0的集合,那么会造成下标越界.所以我们要对集合进行修改
//构造一个指定长度的集合.
public MyArrayList(int capacity) {
if(capacity>0){
DEFAULT_CAPACITY = capacity;
}this.elements = new Object[DEFAULT_CAPACITY ];
}
如果我们添加元素时,已经超过了数组的下标,也是会报错的.接下来我们要做对数组的扩建.
我们引入另一个临时的数组
//临时存储元素的数组
private Object[] tempElements;
并且修改add()方法
//添加元素
public boolean add(E e) {
//现在数组已经满了
if (index==elements.length){
tempElements = new Object[elements.length+DEFAULT_CAPACITY]; //接着我们需要将已经有的元素copy到新数组内
for(int x=0;x<elements.length;x++){
tempElements[x] = elements[x];
} //然后我们将老的数组重新创建
elements = new Object[elements.length+DEFAULT_CAPACITY];
//最后我们将临时数组的元素,重新放置到新数组中
for(int x=0;x<tempElements.length;x++){
elements[x] = tempElements[x];
} }
//设置元素到指定下标位置
elements[index] = e;
//下标自增
index++;
return true;
}
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(0);
myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(3);
myArrayList.add(4);
System.out.println(myArrayList.size());//
}
}
此时我们的集合,则有了自动扩建大小的功能.
接下来我们来实现一个get()
//获取指定下标的元素
public E get(int index){
return (E)elements[index];
}
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(3);
myArrayList.add(1);
System.out.println(myArrayList.get(0));//
System.out.println(myArrayList.get(1));//null
System.out.println(myArrayList.get(2));//null
System.out.println(myArrayList.get(3));// java.lang.ArrayIndexOutOfBoundsException: 3
}
}
这个结果显然不是我们想要的,我们初始化一个大小为3的集合,并且设置1个元素,此时我们只添加一个元素.其他两个为null,原因是我们创建的Object数组,数组中没有元素默认值它就是null,至于下标越界则是正常情况.此时我们应该加一个限制.
//获取指定下标的元素
public E get(int index) {
if (index >= this.index) {
throw new RuntimeException("您访问了不存在的元素,当前元素个数最大为" + this.index + "");
}
return (E) elements[index];
}
此处抛出一个RuntimeException,运行时异常模仿JDK中,不让用户try,catch异常.
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(3);
myArrayList.add(1);
System.out.println(myArrayList.get(0));//
System.out.println(myArrayList.get(1));//您访问了不存在的元素,当前元素个数最大为1
}
}
同样我们的set()方法也应该具备检验的能力,所以我们将检验的代码抽离出来.
//获取指定下标的元素
public E get(int index) {
check(index);
return (E) elements[index];
} //替换指定位置的元素
public E set(int index, E e) {
check(index);
E old = (E) elements[index];
elements[index] = e;
return old;
} //检验下标是否越界
private void check(int index) {
if (index >= this.index) {
throw new RuntimeException("您访问了不存在的元素,当前元素个数最大为" + this.index + "");
}
}
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(3);
myArrayList.add(1);
System.out.println(myArrayList.set(0, 2));//
System.out.println(myArrayList.set(1, 2));//您访问了不存在的元素,当前元素个数最大为1
}
}
实现根据下标删除元素
//删除指定位置的元素
public E remove(int index) {
check(index);
/*
* 删除指定下标的元素
* 1 创建一个新的数组,大小为删除元素后的数组大小.
* 2 将下标前的数组元素取出
* 3 将下标后的数组元素取出
* */
E removeObj = (E) elements[index];
Object[] newObj = new Object[this.index];
for (int i = 0; i < index; i++) {
newObj[i] = elements[i];
}
for (int i = index + 1; i < this.index; i++) {
newObj[i - 1] = elements[i];
}
elements = newObj; return removeObj;
}
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(3);
myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(3);
myArrayList.add(4);
myArrayList.add(5);
Integer remove = myArrayList.remove(3);
System.out.println(remove);//
System.out.println(myArrayList.get(0));//
System.out.println(myArrayList.get(1));//
System.out.println(myArrayList.get(2));//
System.out.println(myArrayList.get(3));// }
}
至此我们还差最后一个东西,迭代.我们要遍历集合
public class Main {
public static void main(String[] args) {
MyArrayList<Integer> myArrayList = new MyArrayList(3);
myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(3);
myArrayList.add(4);
myArrayList.add(5);
for (Object i:myArrayList){
System.out.println(i);
}
}
}
我们要用增强for,但是呢,这个增强for需要集合实现一个接口
public class MyArrayList<E> implements Iterable
这个接口需要实现一个方法,这个方法需要返回一个Iterator
@Override
public Iterator iterator() {
return new MyIterator();
}
class MyIterator implements Iterator{
@Override
public boolean hasNext() {
return false;
} @Override
public Object next() {
return null;
}
}
这里我们使用一个内部类,这个内部类实现Iterator.下边我们要把这两个方法给实现了.
class MyIterator implements Iterator{
int i = 0;
@Override
public boolean hasNext() {
if(index>i){
return true;
}
return false;
} @Override
public Object next() {
return elements[i++];
}
}
其实呢,这个所谓的迭代器,维护的就是一个指针,hasNext()就是判断有没有下一个元素,那就是判断elements的index下标.每次next()执行就把指针自增1.
到此一个简单的ArrayList就完成了.
最后附录一个完整的代码
import java.util.Iterator; public class MyArrayList<E> implements Iterable {
/*
* 注意ArrayList的大小是可变的,此处设定的数组大小为默认大小,和每次扩建的大小
* */ //默认的数组大小
private int DEFAULT_CAPACITY = 1; //存储元素的数组
private Object[] elements; //临时存储元素的数组
private Object[] tempElements; //当前下标默认值
private int index = 0; //构造一个默认长度的集合
public MyArrayList() {
this.elements = new Object[DEFAULT_CAPACITY];
} //构造一个指定长度的集合.
public MyArrayList(int capacity) {
if (capacity > 0) {
DEFAULT_CAPACITY = capacity;
}
this.elements = new Object[DEFAULT_CAPACITY];
} //添加元素
public boolean add(E e) {
//现在数组已经满了
if (index == elements.length) {
tempElements = new Object[elements.length + DEFAULT_CAPACITY]; //接着我们需要将已经有的元素copy到新数组内
for (int x = 0; x < elements.length; x++) {
tempElements[x] = elements[x];
} //然后我们将老的数组重新创建
elements = new Object[elements.length + DEFAULT_CAPACITY];
//最后我们将临时数组的元素,重新放置到新数组中
for (int x = 0; x < tempElements.length; x++) {
elements[x] = tempElements[x];
} }
//设置元素到数组
elements[index] = e;
//将下标自增
index++;
return true;
} //返回当前集合长度
public int size() {
return index;
} //获取指定下标的元素
public E get(int index) {
check(index);
return (E) elements[index];
} //替换指定位置的元素
public E set(int index, E e) {
check(index);
E old = (E) elements[index];
elements[index] = e;
return old;
} //检验下标是否越界
private void check(int index) {
if (index >= this.index) {
throw new RuntimeException("您访问了不存在的元素,当前元素个数最大为" + this.index + "");
}
} //删除指定位置的元素
public E remove(int index) {
check(index);
/*
* 删除指定下标的元素
* 1 创建一个新的数组,大小为删除元素后的数组大小.
* 2 将下标前的数组元素取出
* 3 将下标后的数组元素取出
* */
E removeObj = (E) elements[index];
Object[] newObj = new Object[this.index];
for (int i = 0; i < index; i++) {
newObj[i] = elements[i];
}
for (int i = index + 1; i < this.index; i++) {
newObj[i - 1] = elements[i];
}
elements = newObj; return removeObj;
} @Override
public Iterator iterator() {
return new MyIterator();
} class MyIterator implements Iterator{
int i = 0;
@Override
public boolean hasNext() {
if(index>i){
return true;
}
return false;
} @Override
public Object next() {
return elements[i++];
}
}
}
造轮子ArrayList的更多相关文章
- 跟我一起造轮子 手写springmvc
原创地址:https://www.cnblogs.com/xrog/p/9820168.html 作为java程序员,项目中使用到的主流框架多多少少和spring有关联,在面试的过程难免会问一些spr ...
- 别在重复造轮子了,几个值得应用到项目中的 Java 开源库送给你
我是风筝,公众号「古时的风筝」.文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面.公众号回复『666』获取高清大图. 风筝我作为一个野路子开发者,直到 ...
- 避免重复造轮子的UI自动化测试框架开发
一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...
- 【疯狂造轮子-iOS】JSON转Model系列之二
[疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...
- 【疯狂造轮子-iOS】JSON转Model系列之一
[疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...
- h5engine造轮子
基于学习的造轮子,这是一个最简单,最基础的一个canvas渲染引擎,通过这个引擎架构,可以很快的学习canvas渲染模式! 地址:https://github.com/RichLiu1023/h5en ...
- 我为什么还要造轮子?欠踹?Monk.UI表单美化插件诞生记!
背景 目前市场上有很多表单美化的UI,做的都挺不错,但是他们都有一个共同点,那就是90%以上都是前端工程师开发的,导致我们引入这些UI的时候,很难和程序绑定.所以作为程序员的我,下了一个决定!我要自己 ...
- 「iOS造轮子」之UIButton 用Block响应事件
俗语说 一个不懒的程序员不是好程序员 造轮子,也只是为了以后更好的coding. coding,简易明了的代码更是所有程序员都希望看到的 无论是看自己的代码,还是接手别人的代码 都希望一看都知道这代码 ...
- 重复造轮子感悟 – XLinq性能提升心得
曾经的两座大山 1.EF 刚接触linq那段时间,感觉这家伙好神奇,语法好优美,好厉害.后来经历了EF一些不如意的地方,就想去弥补,既然想弥补,就必须去了解原理.最开始甚至很长一段时间都搞不懂IQue ...
随机推荐
- Java中的集合-您必须知道的13件事
Java Collections Framework是Java编程语言的核心部分之一.集合几乎用于任何编程语言中.大多数编程语言都支持各种类型的集合,例如List, Set, Queue, Stack ...
- Hbase内存磁盘大致关系
转自: https://blog.csdn.net/wuwenxiang91322/article/details/51595771 Hbase内存磁盘关系磁盘数 diskNum磁盘容量 diskCa ...
- Express中app.use()用法 详解
app.use(path,callback)中的callback既可以是router对象又可以是函数 app.get(path,callback)中的callback只能是函数 当一个路由有好多个子路 ...
- 为何我建议1-3年的Java程序员仔细看看这篇文章
此文的目的是为了督促自己去不断学习,让自己有更明确的方向去提升自己.以技能树为基础,以面试要点为大纲,我觉得比抓住什么看什么要更有目的,更能坚持下去.世界瞬息万变,我们要时刻准备着.时刻提高着自己,才 ...
- 关于Maven+Tomcat7下cannot be cast to javax.servlet.Servlet问题的解决办法
今天在开发 JavaWeb 项目的时候,遇到了这么一个问题,这个错误是我在进行表单的异步提交的时候出现的.无法转化为 Servlet 经过我的一番检查之后!没有发现任何问题.... 注解配置无误 继承 ...
- pandas 学习 第7篇:DataFrame - 数据处理(应用、操作索引、重命名、合并)
DataFrame的这些操作和Series很相似,这里简单介绍一下. 一,应用和应用映射 apply()函数对每个轴应用一个函数,applymap()函数对每个元素应用一个函数: DataFrame. ...
- java高并发系列 - 第8天:线程组
线程组 我们可以把线程归属到某个线程组中,线程组可以包含多个线程以及线程组,线程和线程组组成了父子关系,是个树形结构,如下图: 使用线程组可以方便管理线程,线程组提供了一些方法方便方便我们管理线程. ...
- Fiddler 插件开发,使用 WPF 作为 UI 控件
Fiddler 插件的 UI,本身使用的 WinForm,这个例子是使用 WinForm 中的 WPF 容器,将 WPF 控件作为 Fiddler 插件的 UI 使用. 为什么使用 WPF ?为了自适 ...
- MongoDB 高级教程
MongoDB 关系 MongoDB 的关系表示多个文档之间在逻辑上的相互联系. 文档间可以通过嵌入和引用来建立联系. MongoDB 中的关系可以是: 1:1 (1对1) 1: N (1对多) N: ...
- iOS 国际本地化(对新项目集成和已有项目集成)
第一推荐一篇金先生的博客,受益非浅,在这里真诚的感谢 https://www.jianshu.com/p/7cb0fad6d06f金小白 首先金小白先生把两种方式都做了介绍,第一种我就不在过多详细的讲 ...