Collection类之详解(一)

Collection类之详解(一)

一、概述

Collection 层次结构 中的根接口。

由来

由于数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,所以java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少。

数组和集合的区别
区别1 : 
        数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值
        集合只能存储引用数据类型(对象),集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象
区别2:
        数组长度是固定的,不能自动增长
        集合的长度的是可变的,可以根据元素的增加而增长

以Collection的一个实现类ArrayList为例,其中当数组长度不够时,长度扩大代码如下:

//transient关键字的作用:让某些被修饰的成员属性变量不被序列化
//序列化:将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据和信息,可被写到数据库或文件中。
transient Object[] elementData;
private void grow(int minCapacity) {
        // overflow-conscious code
        //旧容量为当前数组中元素个数
        int oldCapacity = elementData.length;
        //新容量=旧容量+旧容量的1/2,即3/2倍的旧容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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);
    }

数组和集合什么时候用
        如果元素个数是固定的推荐用数组
        如果元素个数不是固定的推荐用集合

Collection层次结构图

二、基本功能函数(以下均以ArrayList中实现为例)

 boolean add(E e)
          确保此 collection 包含指定的元素(可选操作)。
boolean remove(Object o)
          从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
 void clear()
          移除此 collection 中的所有元素(可选操作)。
 boolean contains(Object o)
          如果此 collection 包含指定的元素,则返回 true。
 boolean isEmpty()
          如果此 collection 不包含元素,则返回 true。
 int size()
          返回此 collection 中的元素数。

(1)public boolean add(E e)

transient Object[] elementData;
private int size;
public boolean add(E e) {
        //判断是否超过数组大小,如果超过,扩大数组
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

注:add()方法如果是List集合一直都返回true,因为List集合中是可以存储重复元素的 ;

如果是Set集合当存储重复元素的时候,就会返回false;

在开发中一般忽略返回值。

(2)public boolean remove(Object o)

public boolean remove(Object o) {
        //存才对象o时,移除并返回true;否则返回false
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
//已从结构上修改 此列表的次数。从结构上修改是指更改列表的大小,或者打乱列表,从而使正在进行的迭代产生错误的结果。 
//此字段由 iterator 和 listIterator 方法返回的迭代器和列表迭代器实现使用。
protected transient int modCount = 0;

//私有方法,仅可以被类中成员方法调用
private void fastRemove(int index) {
        modCount++;
        //需要移动的元素的个数,即删除位置之后的元素个数
        int numMoved = size - index - 1;
        //将删除位置之后的元素向前移动一个
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        //长度-1,最后一个值赋值为空,垃圾等待GC回收
        elementData[--size] = null; // clear to let GC do its work
    }

(3)public void clear()

public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

(4)public boolean contains(Object o)

public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

public int indexOf(Object o) {
        //遍历寻找,并返回所在位置索引值
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        //如果不存在,返回-1
        return -1;
    }

(5)public boolean isEmpty()

public boolean isEmpty() {
        return size == 0;
    }

(6)public int size()

public int size() {
        return size;
    }

注:ArrayList的父类的父类AbstractCollection重写了toString()方法,调用时返回的是集合中内容。

三、集合的遍历

把集合转成数组,可以实现集合的遍历

Object[] arr = c.toArray();						//将集合转换成数组
for(int i = 0; i < arr.length; i++) {
	System.out.println(arr[i]);
}

注:toArray()返回的是Object[]数组,如果需要用到子类具体方法,可以进行向下转型。

Object[] arr = c.toArray();					//将集合转换成数组
for (int i = 0; i < arr.length; i++) {
	Student s = (Student)arr[i];			//向下转型
	System.out.println(s.getName() + "..." + s.getAge());
}

四、带All的功能函数

 boolean addAll(Collection<? extends E> c)
          将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
 boolean removeAll(Collection<?> c)
          移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
 boolean containsAll(Collection<?> c)
          如果此 collection 包含指定 collection 中的所有元素,则返回 true。
 boolean retainAll(Collection<?> c)
          仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }
//差集
public boolean removeAll(Collection<?> c) {
        //如果c为null,则抛出异常
        Objects.requireNonNull(c);
        //如果c中不包含this中某元素则保留
        return batchRemove(c, false);
    }

//并集
public boolean retainAll(Collection<?> c) {
        //如果c为null,则抛出异常
        Objects.requireNonNull(c);
        //如果c中包含this中某元素则保留
        return batchRemove(c, true);
    }

//Objects类中
public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }


private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        //开始设置为未修改
        boolean modified = false;
        try {
            for (; r < size; r++)
                //按需保留所需元素
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // 即使c.contains()抛出异常,也要保持与AbstractCollection的行为兼容性
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            //未抛出异常,循环完成
            if (w != size) {
                // clear to let GC do its work
                //将不需要的元素赋值为空,等待垃圾回收机制回收
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                //调整已修改次数
                modCount += size - w;
                //调整大小
                size = w;
                //设置为已修改过
                modified = true;
            }
        }
        return modified;
    }
public boolean containsAll(Collection<?> c) {
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }

注:

c1.addAll(c2);							//将c2中的每一个元素添加到c1中
c1.add(c2);					    	        //将c2看成一个对象添加到c1中

五、迭代器遍历

1.概述

集合是用来存储元素,存储的元素需要查看,那么就需要迭代(遍历) 。

Iterator类:

对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:

  • 迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。
  • 方法名称得到了改进。

2.案例

Collection类:

 Iterator<E> iterator()
          返回在此 collection 的元素上进行迭代的迭代器。

 Iterator类:

 boolean hasNext()
          如果仍有元素可以迭代,则返回 true。
 E next()
          返回迭代的下一个元素。
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
while(it.hasNext()) {
	System.out.println(it.next());
}

 注:如果需要用子类方法,和数组遍历一样需要向下转型。

3.原理

迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么就需要在每一个类中定义hasNext()和next()方法,这样做是可以的,但是会让整个集合体系过于臃肿。

迭代器是将这样的方法向上抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做的好处有二:

第一规定了整个集合体系的遍历方式都是hasNext()和next()方法;

第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可;

ArrayList类中:

public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E>{
    //......
}

猜你喜欢

转载自blog.csdn.net/qq_40298054/article/details/84751056
今日推荐