为了锻炼思路,巩固之前学的简单知识,试着自己写一下ArrayList类。
用数组来实现ArrayList类。ArrayList类和数组很像,但是数组是定长不可改的,ArrayList不定长。
目录
构造MyArrayList类
添加操作add()
删除操作remove()
查找操作search()
修改操作set()
我用了泛型来构造
package MyArrayList;
/**
* 自己写的ArrayList类
*
* @author july
*
* @param 泛型
*/
class MyArrayList {
private T[] array; // 本质是对数组的操作
private int index=0; // 记录当前最后一个元素的下标
/**
* 无参构造方法
*/
MyArrayList() {
array = (T[]) new Object[10]; // 创建泛型数组,初始长度设为10
}
/**
* 有参构造方法
*
* @param size 存储长度
*/
MyArrayList(int size) {
array = (T[]) new Object[size];
}
}
为了方便之后的操作,这里写两个方法。一个是用于规范其输出格式的toString()方法,一个是类私有的设置集合当前最后一个元素的下标的方法setIndex()
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
for (T obj : array) {// 循环遍历数组
if (obj == null)
break;
sb.append(obj);
sb.append(",");
}
// 去除最后一个逗号
sb.deleteCharAt(sb.length() - 1);
sb.append("]");
return sb.toString();
}
/**
* 设置数组的最后一个元素的下标值
*/
private void setIndex() {
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
index = i - 1; // 记录下最后一个元素的下标
break;
}else {
index=i;//全满时候
}
}
}
我重载了两个添加操作方法,一个是直接添加到末尾,一个是插入操作,插入到某个下标位置。书写时候需要考虑用于实现的数组是否已经满了,如果满了,则需要创建新的更大的数组进行操作。
添加操作:
/**
* 增加元素操作,增加到末尾
*
* @param object
* @return
*/
void add(T object) {
//获取当前数组最后一个下标
setIndex();
if (index == array.length-1) { // 数组满了,需要创建新数组
T[] temp = (T[]) new Object[array.length * 2]; // 创建新数组
System.arraycopy(array, 0, temp, 0, array.length); // 复制数组
// 将array指向新创建的数组
array = temp;
// 重新给index赋值为当前可以插入元素的下标
setIndex();
}
// 插入元素到数组末尾位置
array[index+1] = object;
}
插入操作:
/**
* 插入操作
* @param desIndex 插入位置
* @param obj 插入元素
*/
void add(int desIndex,T obj) {
//先判断下标是否越界
setIndex();
if(desIndex>index+1) {//最后一个位置也可以插入
try {
throw new Exception("下标越界");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(desIndex == index+1) {
//插入到末尾
add(obj);
}else {
//在前面的其他位置插入元素
for(int i=index;i>=desIndex;i--) {
//先把元素向后移动一位,空出需要插入的位置
array[i+1]=array[i];
}
//可以插入元素了
array[desIndex]=obj;
}
}
测试类:
package MyArrayList;
//测试自己写的ArrayList类
public class TestMyArrayList {
public static void main(String[] args) {
//创建整型ArrayList
MyArrayList myInt=new MyArrayList();
myInt.add(0);
myInt.add(1);
myInt.add(2);
myInt.add(3);
myInt.add(4);
myInt.add(5);
System.out.println(myInt.toString());
//创建字符型的ArrayList
MyArrayList myChar=new MyArrayList();
myChar.add("a");
myChar.add("b");
myChar.add("c");
myChar.add("d");
myChar.add("e");
myChar.add("f");
myChar.add("g");
System.out.println(myChar.toString());
}
}
插入操作的效果:
myInt.add(0, -1);
myChar.add(0, "start");
删除操作我重载了两种,一种是删除某个下标的值,另一个是根据值查找然后删除。删除某位置的元素后要把后面的部分往前移动占掉空的位置
根据下标删除:(需要注意下标是否越界)
/**
* 删除操作
*
* @param desIndex 需要删除的元素下标
*/
void remove(int desIndex) {
if (array[desIndex] == null) {
// 该下标位置没有值
try {
throw new Exception("该位置没有值,无法进行删除操作");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
array[desIndex] = null; // 先删除该处的值
for (int i = desIndex; i <= index; i++) { // 移动后面的值,填补删除的地方
array[i] = array[i + 1];
}
// 把最后一个位置置空
array[index + 1] = null;
}
}
根据值查找来删除:(需要注意该值是否存在)
这里使用了自己写的查找函数(写在下面了)
/**
* 删除操作 注:如果有多个相同的元素,只删除第一个
*
* @param obj 需要删除的元素
*/
void remove(T obj) {
// 调用查找方法寻找该值的下标
int i = search(obj);
if (i != -1) {
remove(i); // 直接调用前面方法来删除
} else {
// 没有找到
try {
throw new Exception("没有找到该元素");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
查看效果:
//根据下标删除
myInt.remove(4);
myChar.remove(4);
//根据值查找删除
myInt.remove((Integer)14);
myChar.remove("f");
(坑)注意:因为第一个对象myInt将泛型使用成Integer了,直接写14会自动调用第一个remove方法(根据下标),将抛出异常下标越界,需要显式将int转为Integer才可以使用。
根据值查找,返回下标。若没有找到,返回-1
/**
* 查找
*
* @param object 需要查找的元素
* @return 元素所在下标,若没有找到,返回-1
*/
int search(T object) {
for (int i = 0; i < array.length; i++) {
if (array[i] == object) {
return i;
}
}
return -1;
}
效果查看:
System.out.println(myInt.search(14));
System.out.println(myChar.search("z"));
修改也重载了两种,一种修改某下标的值,一种是传入原值,经过查找修改成新的值
/**
* 修改操作
* @param desIndex 需要修改的下标
* @param obj 修改目标元素
*/
void set(int desIndex,T obj){
//首先判断该下标是否越界
setIndex();
if(desIndex>index) {
try {
throw new Exception("下标越界");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
array[desIndex]=obj;
}
}
/**
* 修改操作
* @param oObj 需要修改的元素值
* @param dObj 修改后的元素值
*/
void set(T oObj,T dObj) {
int i=search(oObj);
if(i==-1) {
//没有找到这个元素
try {
throw new Exception("没有找到这个元素");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
array[i]=dObj;
}
}
查看效果:
//根据下标修改
myInt.set(4, (Integer)4);
myChar.set(0, "A");
//根据值查找修改
myInt.set((Integer)14, (Integer)4);
myChar.set("z", "A");
(顺便试了一下越界的异常)
好了,暂时就这些!