简单的说,容器是一种能够存放对象的一种工具,就比如我们学过的数组一样,它能存放相同类型的数据。下面我讲结合下面这张图,对java自带的常见容器做分析和实现。

新建java一个空列表 java创建一个arraylist_新建java一个空列表

java常见容器

ColectionMap两大类, Colection是序列化的容器,而Map则是基于键值对的容器,这里如果不熟悉的话,可以先只暂时了解一下,然后对于Colection接口,下面又有两个分类,是List和Set,二者很好区别—— List元素可以重复有顺序,Set元素不可重复无顺序,基于他们的实现类有ArrayList、LinkedList和HashSet,而Map的实现类就是HashMap了。

下面我们来分析最简单的ArrayList,首先,它的底层是由数组实现的,因此它在查询方面比较容易,同时,为了解决数组长度有限的问题,ArrayList对它进行了优化,也就是ArrayList的扩容机制,这个我之前已经分析过它的源代码了,基本思想就是:需要扩容时,就给它创建一个新数组,这个数组大小约为原数组的1.5倍,之后拷贝旧数组元素到新数组里面,然后将原来的数组更换为新的数组。详情请查看下面链接哦~

现世安稳:java关于ArrayList扩容机制zhuanlan.zhihu.com


新建java一个空列表 java创建一个arraylist_新建java一个空列表_02


由于ArrayList父类继承了List接口,而List又继承了Colection接口,因此我们可以先从Colection这个接口开始看起,看定义哪些共同的方法。

新建java一个空列表 java创建一个arraylist_System_03

Colection接口

根据方法名,大家都能推出每个方法的功能是什么,其中可能不是很清楚的就是removeAll和retianAll方法,结合下面这个例子,就会知道它们也很容易区分,removeAll是将list1中的包含list2中的元素全部清除,而retainAll则是只保留list1中与list2中相同的部分元素。

ArrayList<Integer> list1=new ArrayList<>();
		list1.add(0);
		list1.add(1);
		list1.add(2);
		System.out.println("list1:"+list1);
		ArrayList<Integer> list2=new ArrayList<>();
		list2.add(1);
		list2.add(2);
		list2.add(3);
		System.out.println("list2:"+list2);
		list1.removeAll(list2);
		System.out.println(list1);

新建java一个空列表 java创建一个arraylist_新建java一个空列表_04

list1中去掉在list2中出现的元素1,2

ArrayList<Integer> list1=new ArrayList<>();
		list1.add(0);
		list1.add(1);
		list1.add(2);
		System.out.println("list1:"+list1);
		ArrayList<Integer> list2=new ArrayList<>();
		list2.add(1);
		list2.add(2);
		list2.add(3);
		System.out.println("list2:"+list2);
		list1.retainAll(list2);
		System.out.println(list1);


新建java一个空列表 java创建一个arraylist_数组_05

list1中保留在list2中也存在的元素1,2

好了,闲话不多说了,我们现在开始一步一步实现我们自定义的ArrayList:

private static final int DEFAULT_CAPACITY = 10;// 默认容量为10; private int size;// 表示实际大小 private Object elementData[];// 代表底层的数组

1、实现MyArrayList的两种构造方式

无参构造:

public MyArrayList01() {//无参时创建默认大小为10的数组
		elementData = new Object[DEFAULT_CAPACITY];
	}

有参构造:

public MyArrayList01(int capacity) {
//需判断传入容量是否有意义
		if (capacity < 0) {
			throw new RuntimeException("容器的容量不能为负数!");
		} else if (capacity == 0) {
			elementData = new Object[DEFAULT_CAPACITY];
		} else {
			elementData = new Object[capacity];
		}

	}

2、add方法实现,并实现扩容机制和泛型的使用

数组实际大小size不停++,会达到默认的容量大小或者自定的capacity大小,此时假如需要再添加元素,就需要对“数组"进行扩容

public void add(E obj) {
		// 什么时候需要扩容?
		if (size == elementData.length) {
			// 怎么样扩容?10->10+10/2
			Object[] newArray = new Object[elementData.length + (elementData.length >> 1)];
			System.arraycopy(elementData, 0, newArray, 0, elementData.length);
			elementData = newArray;
		}
		elementData[size++] = obj;
	}

3、set和get方法实现,加上越界检查处理

public void rangeCheck(int index) {
		// 索引判断异常
		if (index < 0 || index > size - 1) {
			throw new IndexOutOfBoundsException("Index:" + index);
		}
	}

public void set(E element, int index) {
		rangeCheck(index);
		elementData[index] = element;
	}

	public E get(int index) {
		rangeCheck(index);
		return (E) elementData[index];

	}

4、remove两种方式,根据索引和根据对象来移除

根据索引来移除:利用arraycopy函数将数组elementData从Index+1的位置开始,将其后面的所有元素,长度为elementData.length-Index-1,全部拷贝到elementData数组Index开始到后面的地方。

新建java一个空列表 java创建一个arraylist_新建java一个空列表_06

remove(int Index)示意图

public void remove(int Index) {
		rangeCheck(Index);
		int numMoved = elementData.length - Index - 1;
		if (numMoved > 0) {
			System.arraycopy(elementData, Index + 1, elementData, Index, numMoved);
		}
		elementData[--size] = null;
	}

根据对象来移除:只要用equals方法比较元素即可,然后再利用根据索引删除的方法实现。


public void remove(E element) {
		// element,将它与所有元素接个比较,获得第一个比较为true的删掉
		for (int i = 0; i < size; i++) {
			if (element.equals(get(i))) {
				// 容器中比较都使用equals方法
				// 将该元素从此处移除
				remove(i);
			}
		}
	}


完整测试代码如下:


package myArrayList;

/**
 * 了解底层ArrayList操作后,写出自己的ArrayList 
 * 1、实现add,remove,get,set ; 
 * 2、根据扩容机制实现add;
 * 3、利用泛型实现数据对象参数化;
 * 
 * @author Dell
 *
 */
public class MyArrayList01<E> {

	private static final int DEFAULT_CAPACITY = 10;// 默认容量为10;
	private int size;// 表示实际大小
	private Object elementData[];// 代表底层的数组

	public MyArrayList01() {
		elementData = new Object[DEFAULT_CAPACITY];
	}

	public MyArrayList01(int capacity) {

		if (capacity < 0) {
			throw new RuntimeException("容器的容量不能为负数!");
		} else if (capacity == 0) {
			elementData = new Object[DEFAULT_CAPACITY];
		} else {
			elementData = new Object[capacity];
		}

	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (int i = 0; i < size; i++) {
			sb.append(elementData[i] + ",");
		}
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static void main(String[] args) {
		MyArrayList01<String> myAL = new MyArrayList01<>();
		for (int i = 0; i < 11; i++) {
			myAL.add("tyl_" + i);
		}
		System.out.println(myAL);
		System.out.println(myAL.get(2));
		myAL.set("Hi!", 1);
		System.out.println(myAL);
		myAL.remove(2);
		System.out.println(myAL);
		myAL.remove("Hi!");
		System.out.println(myAL);
      
       
	}

	public void add(E obj) {
		// 什么时候需要扩容?
		if (size == elementData.length) {
			// 怎么样扩容?10->10+10/2
			Object[] newArray = new Object[elementData.length + (elementData.length >> 1)];
			System.arraycopy(elementData, 0, newArray, 0, elementData.length);
			elementData = newArray;
		}
		elementData[size++] = obj;
	}

	public void rangeCheck(int index) {
		// 索引判断异常
		if (index < 0 || index > size - 1) {
			throw new IndexOutOfBoundsException("Index:" + index);
		}
	}

	public void set(E element, int index) {
		rangeCheck(index);
		elementData[index] = element;
	}

	public E get(int index) {
		rangeCheck(index);
		return (E) elementData[index];

	}

	public void remove(E element) {
		// element,将它与所有元素接个比较,获得第一个比较为true的删掉
		for (int i = 0; i < size; i++) {
			if (element.equals(get(i))) {
				// 容器中比较都使用equals方法
				// 将该元素从此处移除
				remove(i);
			}
		}
	}

	public void remove(int Index) {
		rangeCheck(Index);
		int numMoved = elementData.length - Index - 1;
		if (numMoved > 0) {
			System.arraycopy(elementData, Index + 1, elementData, Index, numMoved);
		}
		elementData[--size] = null;

	}

}


新建java一个空列表 java创建一个arraylist_新建java一个空列表_07

测试结果