造轮子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 ...
随机推荐
- H5生成二维码
要用H5生成二维码: 1.引入js库,可自行点击链接复制使用 <script type="text/javascript" src="http://static.r ...
- 17-REST framework-Request与Response
1.Django REST framework提供的视图的主要作用 1.控制序列化器的执行(检验,保存,转换数据) 2.控制数据库查询的执行 Request与Response 1.Request RE ...
- ElasticStack的入门学习
Beats,Logstash负责数据收集与处理.相当于ETL(Extract Transform Load).Elasticsearch负责数据存储.查询.分析.Kibana负责数据探索与可视化分析. ...
- kafka的主题与消费
同一个消费者组不能同时消费同一个分区的数据 不同分区可以消费同一组不同消费者 同一个消费者可以同时消费多个topicA的数据 Topic和consumer依赖zookeeper,producer不依赖
- HTTP中的2XX状态码
HTTP状态码分类 1XX --信息,服务器收到请求,需要请求者继续执行操作 2XX--成功,操作被成功接收并处理 3XX--重定向,需要进一步的操作以完成请求 4XX--客户端错误,请求包含语法错误 ...
- xml的解析(概述)
使用java解析xml☆☆☆ 四个类:分别是针对dom和sax解析使用的类 -dom : DocumentBuilder:解析器类 -这个类是个抽象类,不能new, ...
- JavaScript初探 二 (了解数据)
JavaScript初探 (二) JavaScript 事件 HTML事件 HTML事件是可以在浏览器或用户做的某些事情 HTML事件的例子: HTML网页完成加载 HTML输入字段被修改 HTML按 ...
- SQLi-LABS Page-3 (Stacked injections) Less-38-Less-45
Less-38 堆叠注入原理简介堆叠注入简介 Stacked injections: 堆叠注入.从名词的含义就可以看到应该是一堆 sql 语句(多条)一起执行.而在真实的运用中也是这样的, 我们知道在 ...
- [N久以前发布的文章]php 获取yahoo股票csv数据并封闭成为接口输出json数据
思路 先从yahoo接口获取数据,再定义接口,转化成为json输出.只供卡通网(kt5.cn)使用 stock.php 接口处理代码 <?php header("Content-Typ ...
- mssql sqlserver 使用sql脚本剔除数据中的tab、空格、回车等特殊字符的方法分享
摘要: 在sqlserver开发中,常常有同事反馈无法剔除空格,我们可以通过仔细检查发现,并不是空格字符,而是tab键,如下所示: 解决方法: 对于这些特殊字符的替换,我们需采用字符所对应的ascii ...