不管是顺序表仍是链表,它们都是线性表,都须要进行增删改查操做。
因此首先,定义一个线性表接口List,包含线性表的操做数组
/** * 线性表接口 * 和存储结构无关(顺序表,链表) */ public interface List { //返回线性表的大小,即元素的个数 public int size(); //返回线性表中序号为i 的数据元素 public Object get(int i); //若是线性表为空,返回true,不然返回false public boolean isEmpty(); //判断线性表中是否包含数据元素e public boolean contains(Object e); //返回数据元素e 在线性表中的序号 public int indexOf(Object e); //将数据元素e 插入到线性表中i 号位置 public void add(int i, Object e); //将数据元素e 插入到线性表末尾 public void add(Object e); //将数据元素e 插入到元素obj 以前 public boolean addBefore(Object obj, Object e); //将数据元素e 插入到元素obj 以后 public boolean addAfter(Object obj, Object e); //删除线性表中序号为i 的元素,并返回之 public Object remove(int i); //删除线性表中第一个与e 相同的元素 public boolean remove(Object e); //替换线性表中序号为i 的数据元素为e, 返回原数据元素 public Object replace(int i, Object e); }
private Object[] elementData; //底层是一个数组,目前尚未肯定长度 private int size; //不是数组分配了几个空间,而是数组中元素的个数
public ArrayList(int initalCapacity) { //给数组分配指定数量的空间 elementData = new Object[initalCapacity]; //指定顺序表的元素个数,默认是0 // size = 0; } public ArrayList() { //没有指定长度,默认长度是4 this(4); }
以上代码写完,就能够建立顺序表了,可是里面的操做方法尚未实现安全
public void add(int i, Object e) { //i 的位置要正确 if (i<0 || i > size){ throw new MyArrayIndexOutOfBoundsException("数组索引越界异常:"+i); } //数组元素个数等于数组长度时,须要扩容 if(size == elementData.length){ //扩容方法 grow(); } //后移i 及其后面的元素,从最后一个元素开始 for (int j = size; j > i ; j--) { elementData[j] = elementData[j-1]; } //给数组第i 个位置赋值 elementData[i] = e; //数组元素个数+1 size++; }
首先判断索引是否正确,不正确就抛出一个自定义异常app
public class MyArrayIndexOutOfBoundsException extends RuntimeException { public MyArrayIndexOutOfBoundsException() { } public MyArrayIndexOutOfBoundsException(String message) { super(message); } }
而后当数组元素个数等于数组长度时,调用grow()方法进行扩容,grow()方法有两种实现ui
//基本思路是这样 private void grow(){ //建立一个新数组,长度是旧数组2倍 Object[] newArr = new Object[elementData.length * 2]; //将旧数组数据拷贝到新数组 for (int i = 0; i < size; i++) { newArr[i] = elementData[i]; } //让旧数组 指向 新数组 elementData = newArr; } //一步到位 private void grow(){ //扩容 拷贝 赋值 elementData = Arrays.copyOf(elementData, elementData.length * 2); }
最后实现添加操做:须要从数组尾部元素开始,将第i 位及其以后的元素向后移一位,而后把e 赋值给第i 个位置的元素,最后数组元素个数+1this
public void add(Object e) { this.add(size, e); }
public Object get(int i) { if (i < 0 || i >= size) {//i < 0 或者 i >= size throw new MyArrayIndexOutOfBoundsException("数组索引越界异常:" + i); } return elementData[i]; }
判断索引是否正确,错误抛出自定义异常线程
public Object remove(int i) { if (i < 0 || i >= size) { throw new MyArrayIndexOutOfBoundsException("数组越界异常:"+ i); } Object empt = elementData[i]; for (int j = i; j < size; j++) { elementData[j] = elementData[j+1]; } elementData[size-1] = null; size--; return empt; }
public String toString() { if (size == 0){ return "[]"; } StringBuilder builder = new StringBuilder("["); for (int i = 0; i < size; i++) { if (i != size - 1){ builder.append(elementData[i]+","); }else { builder.append(elementData[i]); } } builder.append("]"); return builder.toString(); }
StringBuffer和StringBuilder很是相似,均表明可变的字符序列。 这两个类都是抽象类AbstractStringBuilder的子类,方法几乎如出一辙。
StringBuffer 线程安全,作线程同步检查, 效率较低。
StringBuilder 线程不安全,不作线程同步检查,所以效率较高。 建议使用该类。code
数组扩容、元素前移、后移索引
ArrayList源码中扩容为50%接口
int newCapacity = oldCapacity + (oldCapacity >> 1);