java集合——java Collection,学习集合,要理解java集合框架,熟练使用java.util包中的相关类与接口进行程序开发。
1、类集框架
java.util包中包含java 2中新增的功能:Collection(集合,类集)。一个类集(Collection)是一组对象。类集的增加使得许多java.util中的成员在结构和体系结构上发生了根本的改变。
2、类集概述
java的类集(或集合)(Collection)框架使你的程序处理对象组的方法标准化。在Java 2出现之前,java提供了一些专门的类如Dictionary,Vector,Stack,Properties去存储和操作对象组。它们缺少一个集中统一的主题。而且其提供的方法也没有被设计成易于扩展和能适应新的环境的形式。而类集解决了这些问题。
类集框架被设计用于适应几个目的。首先,这种框架是高性能的。对基本类集(动态数组,链接表,树和散列表)的实现是高效率的。一般很少需要人工去对这些“数据引擎”编写代码(如果有的话)。第二点,框架必须允许不同类型的类集以相同的方式和高度互操作方式工作。第三点,类集必须是容易扩展和/或修改的。为了实现这一目标,类集框架被设计成包含一组标准的接口。对这些接口,提供了几个标准的实现工具(例如LinkedList,HashSet和TreeSet),通常就是这样使用的。如果你愿意的话,也可以实现你自己的类集。为了方便起见,创建用于各种特殊目的的实现工具。一部分工具可以使你自己的类集实现更加容易。最后,增加了允许将标准数组融合到类集框架中的机制。
3、集合框架中的接口(注意图中列出的都是接口)
所谓框架就是一个类库的集合。集合框架就是一个用来表示和操作集合的统一的架构,包含了实现集合的接口与类。(Collection只有子接口没有实现类)
4、除了类集接口之外,类集也使用Comparator,Iterator和ListIterator接口。简单地说,Comparator接口定义了两个对象如何比较;Iterator和ListIterator接口枚举类集中的对象。
5、Collection接口是构造类集框架的基础。它声明所有类集都将拥有的核心方法。因为所有类集实现Collection,所以熟悉它的方法对于清楚地理解框架是必要的。
6、List的实现类ArrayList数组列表
方法:add(),get(),size(),clear(),isEmpty(),remove(),indexOf(),toArray()
public class ArrayListtest { public static void main(String[] args) { ArrayList arrayList =new ArrayList(); arrayList.add("hello"); arrayList.add("world"); arrayList.add("zdy"); arrayList.add("zdy"); System.out.println("----------"); for(int i = 0;i<arrayList.size();i++) { System.out.println(arrayList.get(i)); } arrayList.remove(0); System.out.println("-------"); for(int i = 0;i<arrayList.size();i++) { System.out.println(arrayList.get(i)); } System.out.println(arrayList.indexOf("zdy")); } }
对于add()方法,返回boolean值,add()方法只能添加对象(object),而不能增加原生数据,如不能add(12),需要使用包装类进行包装,像这样add(new Integer(12));remove()方法删掉元素后,后面的元素自动前提。toArray()方法将列表转换为数组,这里需要注意,转换为数组的类型是Object[] 型的
ArrayList list = new ArrayList();
list.add(new Integer(2));
list.add(new Integer(3));
Object[] in = list.toArray();
//不能写成这样 Integer[] in = list.toArray();
ArrayList的toString()方法是打印一个方括号,方括号里面是每个元素的toString()方法的输出结果
ArrayList里面存储的依然是对象的引用,而不是对象本身。
7、源代码分析:
首先定义了两个成员变量:
private transient Object elementData[];
private int size;
提供了两个构造函数(一个不带参数的默认构造函数,一个带有一个int参数的构造函数):
public ArrayList(int initialCapacity){ super(); if(initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } public ArrayList(){ this(10); }
从这里可以看出来,ArrayLit底层使用数组来实现,并且是一个 Object[]类型的,就是elementData,而且初始化一个ArrayList时,默认的数组长度是10.因为是Object类型数组,所以什么类型的对象都能存进去。
再看add()方法
public boolean add(Object o){ ensureCapacity(size + 1); elementData[size++] = o; return true; } public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; elementData = new Object[newCapacity]; System.arraycopy(oldData, 0, elementData, 0, size); } }
由add方法的定义,我们知道为什么原生数据必须经过包装才能使用,因为add参数只能是Object类型的。add方法第一条语句调用ensureCapacity(size + 1);ensureCapacity的作用是来判断数组elementData是否还有空间来容纳新增元素,如果(size + 1)超过了elementData数组的长度,说明无法在往现有数组增加元素了,由前面的学习知道,数组一旦生成就无法改变其大小,所以这时就要生成一个新的elementData数组,数组的长度为int newCapacity
= (oldCapacity * 3)/2 + 1;或者是
newCapacity = minCapacity;,然后将原来的数组数据复制过来,这样就确保新增元素能够添加成功。而size代表了数组中现有元素的个数,也就是列表ArrayList元素的个数。
以上是1.4版本的实现,下面是1.6版本的
public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } }
如果增加的元素的个数超过了10个,那么ArrayList底层会生成一个新数组,长度为原数组的1.5倍+1,然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组中。当新数组无法容纳增加的元素时,重复该过程。
关于get(int index)方法
public E get(int index) { RangeCheck(index); return (E) elementData[index]; } private void RangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); }
执行get方法时,会执行RangeCheck(index)检测,如果所取的元素位置超出了列表元素个数,抛异常:IndexOutOfBoundsException。
关于remove(int index)方法
public E remove(int index) { RangeCheck(index); modCount++; E oldValue = (E) elementData[index]; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }
也是先执行下标检测,保存要删除元素,然后System.arraycopy(elementData, index+1, elementData, index, numMoved);执行元素移位,最后返回删除的元素。
对于ArrayList的删除操作,需要将被删除元素的后续元素向前移动,代价比较高