不管是順序表仍是鏈表,它們都是線性表,都須要進行增刪改查操做。
因此首先,定義一個線性表接口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);