Collection接口之List子接口详解

讲解之前先讨论一个问题:容器类(集合类)可以存储多个数据,既然数组可以存储,为什么需要定义容器类?

数组的弊端:1)长度是不可变的,一旦数组初始化以后,长度就固定了;

     2)若是在多个地方需要存储多个数据,都得特意编写数组的操作方法,如此以来就没有体现DRY原则(Don‘t  repeat  yourself),即为代码的重用性不高!

为了解决这一弊端,Collection接口就诞生出一个子接口-----List接口,封装一些通用的抽象方法来规范并模拟数组元素的基本操作。注意:任何集合框都包含了三大块内容:对外的接口、接口的实现以及对集合运算的算法(底层都对应某一种数据结构算法)


(一)ArrayList实现类的简单介绍:(由于使用过于频繁,不详解,简单介绍)

   ArrayList接口是大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector 类,除了此类是不同步的。)

   注意,此实现不是同步的如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:

List list = Collections.synchronizedList(new ArrayList(...));

ArrayList类源代码分析:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

	//长度为10的Object数组
	private static final int DEFAULT_CAPACITY = 10;

	//初始化,新建一个长度为0的Object数组
	private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA= {};

	//本质上是一个Object数组
	transient Object[] elementData;

	//初始化创建一个长度为0的Object数组
	public ArrayList() {
        	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    	}

	//新创建一个长度为10的Object数组
	private void ensureCapacityInternal(int minCapacity) {
       		if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            		minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        	}

       	 	ensureExplicitCapacity(minCapacity);
    	}

	//在进行第一次add()添加元素时,新创建一个长度为10的Object数组
	public boolean add(E e) {
       		ensureCapacityInternal(size + 1);  // Increments modCount!!
        	elementData[size++] = e;
        	return true;
    	}
	
	//数组的扩容
	private void grow(int minCapacity) {
        	// overflow-conscious code
       		int oldCapacity = elementData.length;
        	int newCapacity = oldCapacity + (oldCapacity >> 1);//增加为原来的1.5倍
        	if (newCapacity - minCapacity < 0)
            		newCapacity = minCapacity;
        	if (newCapacity - MAX_ARRAY_SIZE > 0)
           		 newCapacity = hugeCapacity(minCapacity);
        	// minCapacity is usually close to size, so this is a win:
        	elementData = Arrays.copyOf(elementData, newCapacity);
    	}
}


(二)Vector实现类详解:

  (1)定义Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector的大小可以根据需要增大或缩小,以适应创建Vector后进行添加或移除项的操作。与新 collection 实现不同,Vector 是同步的(ArrayList是不同步的)!

  注意:Vector类底层其实是一个Object数组,Vector类中的方法是支持同步的!并且Vector数组所存储的元素个数大于Vector的容量,就需要扩容,复制操作,一旦扩容,性能就会降低。建议一般使用初始容量!

  (2)Vector类存储原理:

查看源代码:

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
	
	//底层实现也是封装了一个Object数组
	protected Object[] elementData;

	//数组元素个数
	 protected int elementCount;

	//初始化Vector实例对象,默认创建一个长度为10的Object数组
	public Vector() {
        	this(10);
    	}

	//add()添加元素方法,由于每个方法都添加了synchronized修饰,只展示一个
	public synchronized boolean add(E e) {
        	modCount++;
        	ensureCapacityHelper(elementCount + 1);
        	elementData[elementCount++] = e;
        	return true;
    	}

	//数组的扩容
	private void grow(int minCapacity) {
        	// overflow-conscious code
        	int oldCapacity = elementData.length;
        	int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        	if (newCapacity - minCapacity < 0)
            		newCapacity = minCapacity;
        	if (newCapacity - MAX_ARRAY_SIZE > 0)
            		newCapacity = hugeCapacity(minCapacity);
        	elementData = Arrays.copyOf(elementData, newCapacity);
    	}
}


通过源代码分析,发现在Vector类中有一个Object[]类型的数组

protected Object[] elementData;

1)表面上把数据存储到Vector对象中,其实底层实现依然是把数据存储到Object数组中的;

2):我们发现该数组中的元素类型Object类型,意味着集合中只能存储任意类型的对象,集合中只能存储对象,不能存储基本数据类型;

3):集合类中存储的对象,都存储的是对象的引用,而不是对象本身!

Vector类中常用方法:

增加:

boolean add(Object a)//将指定元素添加到该集合的末尾,等价于addElement(Object a)方法;

void add(int index,Object Element)//在指定的位置添加指定的元素;

boolean addAll(Collection c)//把集合c中的元素逐个添加到当前集合中;

删除:

Object remove(int index)//删除指定索引位置的元素,并返回删除之后的元素对象;

boolean remove(Object o)//删除指定的元素;

boolean removeAll(Collection c)//从此集合中移除包含在指定集合c中的所有元素;

boolean retainAll(Collection c)//求两个集合的交集;

修改:

Object set(int index,Object element)//修改当前集合中指定索引位置的元素,返回旧元素;

查询:

int size()//返回集合中的元素个数;

boolean isEmpty()//判断当前集合中元素个数是否为0;

Object get(int index)//获取指定索引处的元素;

Object[] toArray()//将集合中的元素装换为Object数组,本质是提供集合的副本。


重点:ArrayList类和Vector类的区别:

1)在Java7之前,即使使用了new ArrayList()创建对象,一个元素不存在也会初始化一个长度为10的Object数组,浪费空间;并且Vector底层实现和ArrayList等同,一样初始化一个长度为10的Object数组;

2)从Java7开始,ArrayList类使用new ArrayList()创建对象,底层是一个空数组,只是在第一次调用add(Object o)时,才会初始化一个长度为10的Object数组,实现效果会更好一点,防止创建并没有使用,浪费内存空间!

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

3)Vector类中的所有方法都是synchronized关键字修饰的,即多个线程方法同一Vector实例对象是安全的,但是效率很低,速度极慢;

4)ArrayList类中的所有方法非synchronized关键字修饰,但是多线程访问不安全,效率高,速度快;

5)即使在多线程中访问,也不使用Vector类,Collections包装类提供了一个方法,返回一个可同步的线程安全的ArrayList对象:

ArrayList list = Collections.synchronizedList(new ArrayList());


(三)栈(Stack):数据结构的一种,存储特点:先进后出

查看栈的源代码:

public class Stack<E> extends Vector<E> {
	//栈的初始化
	public Stack() {
    	}
	
	//向栈中添加元素
	public E push(E item) {
		//本质上调用Vector中的方法
        	addElement(item);
        	return item;
    	}

	//从栈中弹出一个元素
	public synchronized E pop() {
        	E       obj;
        	int     len = size();
		//调用了该类中获取栈顶的方法
        	obj = peek();
		//本质上调用Vector类中的删除方法
        	removeElementAt(len - 1);

        	return obj;
    	}

	//弹出栈顶元素
	public synchronized E peek() {
		//获取元素总个数
        	int     len = size();

        	if (len == 0)
            	throw new EmptyStackException();
		//本质调用Vector获取指定索引处的元素
        	return elementAt(len - 1);
    	}
	
	//判断栈是否为空
	public boolean empty() {
        	return size() == 0;
    	}
}


(1)根据Stack的源代码,底层实现是Vector数组形式;

(2)Vector类中的add()等方法是实现了List接口统一规范提供的,而addElement()方法是Vector类特有的方法(原始方法),两者功能等同;


由于此篇幅过长,不易阅读,将在下一篇幅中讲解LinkedList接口,以及手动实现一个双向链表

http://blog.csdn.net/super_yc/article/details/73467488

猜你喜欢

转载自blog.csdn.net/super_yc/article/details/73466353