面试官Q1:可以手写一个ArrayList的简单实现吗?

我们都知道ArrayList是基于数组实现,如果让你实现JDK源码ArrayList中add()、remove()、get()方法,你知道如何实现吗?这一节,我们不看源码,我们想想如何简单的实现ArrayList几个基本方法?

确定数据结构

我们知道,ArrayList中无论什么数据都能放,是不是意味着它是一个Object类型,既然是数组,那么是不是Object[]数组类型的?所以我们定义的数据结构如下:

private Object[] elementData;
private int size;

设置自定义的MyArrayList的长度为10

 public MyArrayList(){
this(10);
} public MyArrayList(int initialCapacity){
if(initialCapacity<0){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
elementData = new Object[initialCapacity];
}

有了存放数据的位置,接下来,我们想想如何将数据放入数组?

添加数据

public void add(Object obj){
elementData[size++]=obj;
}

每添加一个元素,size就会自增1,我们定义的数组长度为10,当我们添加到11个元素的时候,显然没有地方存放新添加的数据,这个时候我们需要对数组进行扩容处理对上面代码做如下修改:

 public void add(Object obj){
if(size==elementData.length){
//创建一个新的数组,并且这个数组的长度是原数组长度的2倍
Object[] newArray = new Object[size*2];
//使用底层拷贝,将原数组的内容拷贝到新数组
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
//并将新数组赋值给原数组的引用
elementData = newArray;
}
//新来的元素,直接赋值
elementData[size++]=obj;
}

用一张图来表示就是这样的:

  

查询数据

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

删除数据

接着我们看一下删除的操作。ArrayList支持两种删除方式:

  • 按照下标删除

  • 按照元素删除,这会删除ArrayList中与指定要删除的元素匹配的第一个元素

对于ArrayList来说,这两种删除的方法差不多,都是调用的下面一段代码:

 public void remove(int index){
//删除指定位置的对象
//a b d e
int numMoved = size - index - 1;
if (numMoved > 0){
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
}
elementData[--size] = null; // Let gc do its work
}

其实做的事情就是两件:

  • 把指定元素后面位置的所有元素,利用System.arraycopy方法整体向前移动一个位置

  • 最后一个位置的元素指定为null,这样让gc可以去回收它

用图表示是这样的:

指定位置添加数据

把从指定位置开始的所有元素利用System,arraycopy方法做一个整体的复制,向后移动一个位置(当然先要用ensureCapacity方法进行判断,加了一个元素之后数组会不会不够大),然后指定位置的元素设置为需要插入的元素,完成了一次插入的操作。

public void add(int index,Object obj){
ensureCapacity(); //数组扩容
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = obj;
size++;
}

用图表示这个过程是这样的:

  

  

总结一下

从上面的几个过程总结一下ArrayList的特点:

  • ArrayList底层以数组实现,是一种随机访问模式,通过下标索引定位数据,所以查找非常快

  • ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已(这里指的末尾添加数据)

  • 当删除元素的时候,涉及到一次元素复制移位,如果要复制的元素很多,那么就会比较耗费性能

  • 当插入元素的时候,涉及到一次元素复制移位,如果要复制的元素很多,那么就会比较耗费性能

因此,ArrayList比较适合顺序添加、随机访问的场景。

  

JAVA面试题 手写ArrayList的实现,在笔试中过关斩将?的更多相关文章

  1. 面试必会之ArrayList源码分析&手写ArrayList

    简介 ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高. 线程 ...

  2. 三 基于Java动态数组手写队列

    手写队列: package dataStucture2.stackandqueue; import com.lt.datastructure.MaxHeap.Queue; import dataStu ...

  3. 二 基于java动态数组手写栈

    package dataStucture2.stack; import dataStucture2.array.MyDynamicArray; /** * 基于动态数组手写栈 * 设计时,栈中仅栈顶对 ...

  4. java面试:手写代码

    二分查找法. /** * 二分查找法:给定一组有序的数组,每次都从一半中查找.直到找到要求的数据. * 主要是得找到下标的表示方法. */ public class BinaryFind { /** ...

  5. Java 面试题 自己写的答案

    基本概念 操作系统中 heap 和 stack 的区别 栈(stack)与堆(heap)都是Java用来在内存中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 在函 ...

  6. java面试之手写单例模式

    为什么要有单例模式 实际编程应用场景中,有一些对象其实我们只需要一个,比如线程池对象.缓存.系统全局配置对象等.这样可以就保证一个在全局使用的类不被频繁地创建与销毁,节省系统资源. 实现单例模式的几个 ...

  7. Android 手写Binder 教你理解android中的进程间通信

    关于Binder,我就不解释的太多了,网上一搜资料一堆,但是估计还是很多人理解的有困难.今天就教你如何从 app层面来理解好Binder. 其实就从我们普通app开发者的角度来看,仅仅对于androi ...

  8. Java面试题:写代码使得分别出现StackOverflowError和OutOfMemoryError

    转载自:http://www.cnblogs.com/xudong-bupt/p/3360206.html 今天做了个笔试,这是其中的一道题目:写代码使得分别出现StackOverflowError和 ...

  9. 【Java面试题】32 ArrayList和Vector的区别

    1. Vector & ArrayList  相同点: 1.ArrayList和Vector都是继承了相同的父类和实现了相同的接口 2.底层都是数组实现的 3.初始默认长度都为10. 不同点: ...

随机推荐

  1. Android零基础入门第23节:ImageButton和ZoomButton使用大全

    原文:Android零基础入门第23节:ImageButton和ZoomButton使用大全 上一期我们学习了ImageView的使用,那么本期来学习ImageView的两个子控件ImageButto ...

  2. List<T>多字段排序的一个通用类

    本文中的方法旨在解决通用的问题,非常注重效率的地方,还应该针对具体的类去写排序方法. 废话不多说,直接上代码 具体使用场景: 要排序的类 1 public class bb 2 { 3 public ...

  3. c# winform快捷键实现

    我们在软件中经常用到快捷键,这里整理备份一下. 首先我们要定义可以作为快捷键的按键,以下是整理的 一些,自己可以根据情况来修改 public static Dictionary<int, str ...

  4. FreeCL

    FreeCL 1.03(Free Control Library)是一个开源且免费的Windows控件库,它属于3D图形引擎FreeGE中的一部分,用户可以自由地用于个人或商业开发.FreeCL使用类 ...

  5. IT++数学、信号、通讯类库,Blitz++数学,Armadillo 线性代数,Dlib网络,线程,图形,数学,图像,数据挖掘/机器学习,XML等等

    https://en.wikipedia.org/wiki/Blitz%2B%2B https://en.wikipedia.org/wiki/IT%2B%2B https://en.wikipedi ...

  6. BSTR使用误区以及隐藏的内存破坏和内存泄漏

    BSTR使用误区以及隐藏的内存破坏和内存泄漏 作者:magictong 简介 BSTR的数据结构是什么样子并不是本文讨论的问题,但是却是本文的基础.在解决COM的跨平台编程的问题时,需要定义一种通用的 ...

  7. 从 docker 到 runC

    笔者在前文<RunC 简介>和<Containerd 简介>中分别介绍了 runC 和 containerd.本文我们将结合 docker 中的其它组件探索 docker 是如 ...

  8. hadoop之hbase基本操作

    hbase shell 进入hbase命令行 list 显示HBASE表 status 系统上运行的服务器的细节和系统的状态 version 返回HBase系统使用的版本 table_help 引导如 ...

  9. springboot中加分布式redis锁

    分布式redis锁,spring-boot-starter-data-redis,RedisTemplate 公司聊天的聊天系统,近期出现多个客服并发接待同一个客户的记录,经排查,是由于代码加的同步锁 ...

  10. 附008.Kubernetes TLS证书介绍及创建

    一 Kubernetes证书 1.1 TLS Kubernetes系统的各个组件需要使用TLS证书对其通信加密以及授权认证,建议在部署之前先生成相关的TLS证书. 1.2 CA证书创建方式 kuber ...