造轮子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 ...
随机推荐
- 瓜子IM智能客服系统的数据架构设计(整理自现场演讲)
本文由ITPub根据封宇在[第十届中国系统架构师大会(SACC2018)]现场演讲内容整理而成. 1.引言 瓜子业务重线下,用户网上看车.预约到店.成交等许多环节都发生在线下.瓜子IM智能客服系统的目 ...
- IT兄弟连 Java语法教程 赋值运算符
从本书之前的内容中就一直在使用赋值运算符.现在是正式介绍赋值运算符的时候了.赋值运算符是单个等号”=“.在Java中,赋值运算符的工作方式与所有其它计算机语言相同.它的一般形式如下: var = ex ...
- 《Head First C#》外星人入侵WPF编写源码
目录 引言 前期工作 只要努力没有什么困难可以难倒你,加油骚年! @(外星人入侵(WPF编写)) 引言 自学的C#,看了几本教材讲的都是程序代码,网上找的也有视屏,但都比较老了.只会打些代码为不晓得为 ...
- 通过SSH通道来访问MySQL
许多时候当要使用Mysql时,会遇到如下情况: 1. 信息比较重要,希望通信被加密.2. 一些端口,比如3306端口,被路由器禁用. 对第一个问题的一个比较直接的解决办法就是更改mysql的代码,或 ...
- windows 下使用cmake指定visual studio 版本
https://blog.csdn.net/iceboy314159/article/details/87829950
- JavaScript初探 三 (学习js数组)
JavaScript初探 (三) JavaScript数组 定义 创建数组 var 数组名 = [元素0,元素1,元素2,--] ; var arr = ["Huawei",&qu ...
- Android应用打开外部文件
我们有时候遇到要打开一个文件,我们可以选择用其他应用打开,这时弹出来的应用列表,那么我们如何让自己开发的应用也能出现在里面呢? 第一步:设置启动Activity的intent-filter,给data ...
- [b0027] python 归纳 (十二)_并发队列Queue的使用
# -*- coding: UTF-8 -*- """ 学习队列 Queue 总结: 1. 队列可以设置大小,也可以无限大小 2. 空了,满了,读写时可以阻塞,也可以报错 ...
- canopy聚类算法的MATLAB程序
canopy聚类算法的MATLAB程序 凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 1. canopy聚类算法简介 Canopy聚类算法是一个将对象分组到 ...
- Pwn-level3
题目地址 https://dn.jarvisoj.com/challengefiles/level3.rar.2047525b05c499c9dd189ba212bba1f8 借鉴 https://w ...