Arraylist +Iterator深入了解

1.Arraylist 是什么?

Arraylist 是list的一个实现类,属于一个集合,但是其实际上是在使用几个构造方法,在方法里面实际在操作一个特殊的数组

  public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

  public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }


我们可以从源代码中提取几个构造方法可以看出它实际上实例化了一个objecj的一个数组,所以可以看出他的底层实现的是一个特殊的数组所有的操作也是基于这个数组来进行操作的。

2.用了哪些构造方法?构造方法有什么用?

我们去翻看它的源代码可以很清楚的看到其中有很多构造方法。

其构造方法如下:

public ArrayList(int initialCapacity); //一个可以设置默认初始容量的类的构造方法  
 public ArrayList();//一个初始容量为0的类的构造方法  
 public ArrayList(Collection<? extends E> c);//一个传递参数为集合的类的构造方法
3.默认初始容量和可变长度如何体现?


我们上面所说Arraylist 集合实际在操作一个特殊的数组,为什么是个特殊的数组呢?
可以理解为这个集合有一个默认的容量和它的容量具有可变性?


接下来我们查看源代码来探索一番其中的奥秘,


首先我们来看看调用每个构造方法它其中的默认长度是多少呢?

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //数组长度默认为0;
  public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;  //集合的默认容量为0;
    }

//当我们在调用ArrayList()这个方法的时候可以得出ArrayList集合默认的容量为0;


    private static final Object[] EMPTY_ELEMENTDATA = {}; //数组长度默认为0;
 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {   //判断设置的默认容量是否为0
            this.elementData = new Object[initialCapacity];  //集合的初始容量为设置的容量
        } else if (initialCapacity == 0) {   //判断设置的容量为0
            this.elementData = EMPTY_ELEMENTDATA;  //集合的容量为0;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


//当我们在调用ArrayList(int initialCapacity)这个方法的时候,这个方法是可以设置初始容量的,
//不再是默认的0,当我们设置的容量为1的话,调用这个方法的时候,这个时候的初始容量就为1.
那么如何来体现是个可变长度呢?

首先我们来看看数组的长度是如何变化的?

 private int size; //成员变量,默认为0;
 public boolean add(E e) {
        ensureCapacityInternal(size + 1); 
        elementData[size++] = e;
        return true;
    }

//我们可以看出,每当执行add(E e)这个方法的时候,elementData[size++]这个数组的长度都会+1,从而达到数组长度的变化

那集合的容量是如何变化呢?

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //数组长度默认为0;

private static final int DEFAULT_CAPACITY = 10; //设置个默认值为10的变量

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);   //第一次增量为0-10之内最大的一个数
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)    
            grow(minCapacity);    //当添加数据所占的容量达到极限,调用grow()方法进行增量
    }


 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);
    }

这就是我对Arraylist一个简单的分析



下面来分析一下Iterator迭代器



Iterator迭代器我们都知道通常是用来遍历集合的

但是它是怎么去执行的能?我们来了解一下


Iterator迭代器遍历集合其实是根据数组的下标开始去往下面一一去遍历


 public static void main(String args[]) {
	
		    List ls=new ArrayList();
		    ls.add("1");
		    ls.add("2");
		    ls.add("3");
		 
		Iterator it=ls.iterator();
		while(it.hasNext()) {  //返回一个布尔值,指示重复值中是 (true) 否 (false) 有其它实例
			Object o=it.next();  //iterator迭代器首先是从下标为-1开始遍历,使用next()获得序列中的下一个元素,直至达到下标的最大值
			System.out.println(o);
		}
		
		
		 }

我们都知道for循环和Iterator迭代器都可以来遍历集合,但是它们还是有区别的,

比如我们就拿一个很简单的删除奇数的实例来看看它们的区别

Iterator与for循环进行集合数据的删除奇数比较

package com.zking.list;

import java.util.ArrayList;
import java.util.List;

public class Linklisttest {

	public static void main(String args[]) {
//for循环删除实例
		List ls = new ArrayList();
		ls.add("1");
		ls.add("1");
		ls.add("3");
		ls.add("4");
		ls.add("5");

		for (int i = 0; i < ls.size(); i++) {
			Integer itg = Integer.parseInt((String) ls.get(i));
			if (itg % 2 != 0) {
				ls.remove(i);
			}
		}

		for (Object object : ls) {
			System.out.println(object);
		}

		
	}

}
package com.zking.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Linklisttest {
//Iterator删除实例
	public static void main(String args[]) {

		List ls = new ArrayList();
		ls.add("1");
		ls.add("1");
		ls.add("3");
		ls.add("4");
		ls.add("5");

		Iterator it = ls.iterator();
		while (it.hasNext()) {
			Integer i = Integer.parseInt((String) it.next());
			if (i % 2 != 0) {
				it.remove();
			}
		}
		for (Object object : ls) {
			System.out.println(object);
		}

	}

}

运行结果分别如下:



由此可以看出用for循环删除,第二个奇数1未被删除,而Iterator迭代器则删除了所有的奇数

原因是当for循环删除第一个奇数时,后面的元素位置会往上移一位,所以第二个奇数1顶替的第一个奇数1,由于遍历了第一个元素的位置,被替换后就不再去遍历寻找,所以第二个奇数1不会被删除,而terator迭代器是往下面一一去寻找下面的元素,每个元素不管如何都会被遍历到。



以上就是小白对这些的理解,再接再励吧!!!

猜你喜欢

转载自blog.csdn.net/mr_xiayijie/article/details/80445734
今日推荐