ArrayList的介绍
ArrayList故名意思就是动态数组的意思,它具备了数组的基本属性,除此之外,提供了动态的增加和减少元素,灵活的设置数组的大小等好处.
ArrayList的实现
ArrayList实现了List的接口,底层使用数组来保存其中的元素.了解到这些信息我们我们可以自己实现一个简单的ArrayList
一 .私有属性定义
在ArrayList中我们只需要定义两个私有属性,分别为保存元素的数组和这个数组的长度
private Object[] elementData;//这是一个对象数组! 外部调用需要new
private int size; // 全局变量默认值是0;size是元素的数量,不是容器的容量大小
二 . 数组的初始化
数组的初始化直接写在构造器中,其他没有什么好讲的,请直接看代码
// 无障碍阅读友情提示:initialCapacity=总容量
public MyArrayList(int initialCapacity) {
//如果创建的长度小于零抛异常(数组长度应该大于等于0)
if (initialCapacity < 0) {
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//创建新的数组
this.elementData = new Object[initialCapacity];
}
这里还可以简单优化一下,创建一个无参构造器来调用上面的有参构造器
public MyArrayList() {
//调用上面的有参构造器
this(10);
}
这样每次new 这个对象不用在构造函数里写数组的长度了,起步就是10个;
三 . 数组容量检测
需要数组扩容前必定检测数组的长度,所以这一步也必不可少.
private boolean sizeCheck(){
if (size > elementData.length - 1) // 假设length是10 size是10的情况已经满了
return false;
return true;
}
四 . 扩容原理
因为ArrayList和数组的最大区别就是数组长度一旦定义便不可修改,而ArrayList比较牛逼,可以实现数组长度的改变.但实现原理真的很简单,一句话概括就是“临时创建一个长度更长的数组,将原数组的元素拷贝进新的数组,再将这个新数组赋值给原数组”如果第一次读比较拗口,多读几遍就会明白原来实现是真的很简单.我还没亮出代码,代码可能就浮现在你的脑海之中了.但是我还是要强行贴上代码
private void increaseCapacity(){
//创建一个是原来数组中元素个数?2容量的数组(注意区分数组元素个数和数组长度)
Object[] newArray = new Object[size * 2];
//下面提供两种元素拷贝的方法,一种是自己for循环赋值,一种直接用数组拷贝函数
// for(int i=0;i<elementData.length;i++){
// newArray[i]=elementData[i];
// }
// elementData=newArray;
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
//后排提示 忘了这步可就前功尽弃了
elementData = newArray;
}
五 . 常用方法
因为实现了List的接口,ArrayList也理应具有List的方法,这里给出几个较为常用的方法.
0.输入索引范围检查
因为增删查该都涉及输入的数组下标;所以应该有一个输入数组下标合法性的检查
private void rangeCheck(int index){
if(index>=size){ //index从0开始 比size小 size本来就大于零;
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1.元素的插入
public void add(Object obj) {
//检查是否需要扩容
if(sizeCheck()==false){
increaseCapacity();
}
//增加新的元素,注意size也要增加
elementData[size++] = obj;
}
2 元素的查找
① 输入一个索引,返回该索引对应的元素
public Object get(int index){
rangeCheck(index);
return elementData[index];
}
② 输入一个元素,返回从前往后遇到的第一个此元素的索引;若找不到则返回-1;
public int get(Object obj){
for(int i=0;i<size;i++){
if(obj.equlas(elementData[i]))
return i;
}
return -1;
}
3.元素的删除
① 删除输入索引所对应的元素
删除的原理就是把索引对应的元素删除,该索引以后的元素全都往前挪移一位
移动元素有两种方法如下1 for循环自己移动 2 借助数组拷贝函数
public void remove(int index) { // 当索引为 2的时候 i 0 1 2 3 4
rangeCheck(index);
for(int i=index;i<size-1;i++){
elementData[i]=elementData[i+1]; // i 0 1 3 4 4
}
// System.arraycopy(elementData,index+1, elementData, index, size-(index+1)); index从0开始
elementData[--size]=null;// 最后一个元素是elementData[size-1] =null 同时 size减一,此时size=4
}
② 输入一个元素,删除从前往后遇到的相同的第一个此元素.如果没有遇到就不做修改.
public void remove(Object obj){
for(int i = 0; i<size;i++){
if (obj.equals(elementData[i])){
//调用数组复制函数
System.arraycopy(elementData,i+1, elementData, i, size-(i+1));
elementData[--size]=null;
}
}
}
4.元素的插入
① 输入一个元素和插入到数组的位置
public void insert(Object obj,int index){
//输入数组下标合法性判断
rangeCheck(index);
//判断插入前数组是否已经满了
if(sizeCheck()==false){
increaseCapacity();
}
//把索引位置腾出来(元素向后移动)
for(int i=index;i<size;i++){
elementData[i+1]=elementData[i];
}
//插入元素
elementData[index]=obj;
}
最后总结
无论是ArrayList的原理还是实现方法都是比较简单的,自己多加思索就可以实现其中的增查删改功能, 静下心来看看ArrayList源码后自己实现一个有基本功能的动态数组,无论是对自身的思维方式还是代码能力都有很大的提升.
最后的最后附上源码(凑篇幅???)
public class MyArrayList {
private Object[] elementData;// 这是一个对象数组!
private int size; // 全局变量默认值是0;size是元素的数量,不是容器的容量大小
public MyArrayList(int initialCapacity) {
if (initialCapacity < 0) {
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.elementData = new Object[initialCapacity];
}
public MyArrayList() {
this(10);
}
public void add(Object obj) {
if (sizeCheck() == false) {
increaseCapacity();
}
elementData[size++] = obj;
}
private boolean sizeCheck() {
if (size > elementData.length - 1) // length是10 size是10的情况已经满了
return false;
return true;
}
private void increaseCapacity() {
Object[] newArray = new Object[size * 2];
// for(int i=0;i<elementData.length;i++){
// newArray[i]=elementData[i];
// }
// elementData=newArray;
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
elementData = newArray;
}
public Object get(int index) {
rangeCheck(index);
return elementData[index];
}
public void remove(int index) {
rangeCheck(index);// i 0 1 2 3 4
for (int i = index; i < size - 1; i++) {
elementData[i] = elementData[i + 1]; // i 0 1 3 4 4
}
// System.arraycopy(elementData,index+1, elementData, index,
// size-(index+1));//index从0开始
elementData[--size] = null;// 最后一个元素是elementData[size-1] =null 同时
// size减一,此时size=4
}
public void remove(Object obj) {
for (int i = 0; i < size; i++) {
if (obj.equals(elementData[i])) {
System.arraycopy(elementData, i + 1, elementData, i, size
- (i + 1));
elementData[--size] = null;
}
}
}
public void insert(Object obj, int index) {
rangeCheck(index);
if (false == sizeCheck()) {
increaseCapacity();
}
for (int i = index; i < size; i++) {// 0 1 2 3 4
elementData[i + 1] = elementData[i];
}
elementData[index] = obj;
}
private void rangeCheck(int index) {
if (index >= size) { // index从0开始 比size小 size本来就大于零;
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyArrayList list = new MyArrayList(2);
list.add(123);
list.add(45);
list.add(12133);
list.remove(2);
System.out.println(list.get(1));
}
}