3 Collection
1、 接口特点
Collection 接口的特点是元素是 Object。遇到基本类型数据,需要转换为包装类对象。
2、 基本操作
Collection 接口中常用的基本操作罗列如下:
boolean add(Object o) 这个操作表示把元素加入到集合中。add 方法的返回值为 boolean 类型。如果元素加入集合成功,则返回 true,否则返回 false。
boolean contains(Object o) 这个方法判断集合中是否包含了 o 元素。
boolean isEmpty() 这个方法判断集合是否为空。
Iterator iterator() 这个方法很重要,可以用来完成集合的迭代遍历操作。具体的介绍会在介绍 List接口如何遍历时再强调
boolean remove(Object o) remove 方法表示从集合中删除 o 元素。返回值表示删除是否成功。
void clear() clear 方法清空集合。
int size() 获得集合中元素的个数。
3、 Collection 如何遍历\Collection 的实现类
Collection 没有直接的实现类。也就是说,某些实现类实现了 Collection 接口的子接口,
例如 List、Set,这样能够间接的实现 Collection 接口。但是没有一个实现类直接实现了Collection 接口却没有实现其子接口。
4 List
4.1 List 特点和基本操作
List 接口的特点:元素是对象,并且元素有顺序,可以重复。
对于 List 而言,元素的所谓“顺序”,指的是每个元素都有下标。因此,List 的基本操作,除了从 Collection 接口中继承来的之外,还有很多跟下标相关的操作。
基本操作罗列如下:
boolean add(Object o) / void add(int index, Object element)
在 List 接口中有两个重载的 add 方法。第一个 add 方法是从 Collection 接口中继承而来的,表示的是把 o 元素加入到 List 的
末尾;第二个 add 方法是 List 接口特有的方法,表示的是把元素 element 插入到集合中 index 下标处。
Object get(int index) / Object set(int index, Object element)
get 方法获得 List 中下标为 index 的元素,set方法把 List 中下标为index 的元素设置为 element。利用这两个方法,可以对 List 根据相应下标进行读写。
int indexOf(Object o)
这个方法表示在 List 中进行查找。如果 List 中存在 o 元素,则返回相应的下标。如果 List 中不存在 o 元素,则返回-1。
这个方法可以用来查找某些元素的下标。
除此之外,List 接口中还有一些诸如 size、clear、isEmpty 等方法,这些方法与介绍Collection 接口中的相应方法含义相同,在此不再赘述。
4.2 遍历
首先,为了能使用 List 接口,必须先简单介绍一个 List 接口的实现类:ArrayList。这个类使用数组作为底层数据结构,实现了 List 接口,我们使用这个类来演示应该如何对 List进行遍历。
public class TestArrayList { public static void main(String args[]){ List list = new ArrayList(); list.add("hello"); list.add("world"); list.add("java"); list.add("study"); for(int i = 0; i<list.size(); i++){ System.out.println(list.get(i)); } } }
4.2.1 迭代遍历
迭代遍历是 Java 集合中的一个比较有特色的遍历方式。这种方法被用来遍历 Collection接口,也就是说,既可以用来遍历 List,也可以用来遍历 Set。
使用迭代遍历时,需要调用集合的 iterator 方法。这个方法在 Collection 接口中定义,也就是说,List 接口也具有 iterator 方法。
这个方法的返回值类型是一个 Iterator 类型的对象。Iterator 是一个接口类型,接口类型没有对象,由此可知,调用 iterator 方法,返回的一定是 Iterator 接口的某个实现类的对象。这是非常典型的把多态、接口用在方法的返回值上面。Iterator 接口表示的是“迭代器”类型。利用迭代器,我们可以对集合进行遍历,这种遍历方式即称之为迭代遍历。
public class TestArrayList { public static void main(String args[]){ List list = new ArrayList(); list.add("hello"); list.add("world"); list.add("java"); list.add("study"); Iterator iter = list.iterator(); } }
在调用 list 的 iterator 方法之后,返回一个 Iterator 类型的对象。这个对象就好像一个指针,指向第一个元素之前。如下图:
在迭代器中定义了两个方法:
boolean hasNext()
这个方法返回一个 boolean 类型,表示判断迭代器右方还有没有元素。对于上面这种情况,对迭代器调用 hasNext()方法,返回值为 true。
Object next()
这个方法,会把迭代器向右移动一格。同时,这个方法返回一个对象,这个对象就是迭代器向右移动时,跳过的那个对象。如下图:
调用一次 next 方法之后,迭代器向右移动一位。在向右移动的同时,跳过了“hello”这个元素,于是这个元素就作为返回值返回。
我们可以再持续的调用 next()方法,依次返回“world”,“java”,“study”对象,直至hasNext()方法返回 false,意味着迭代器已经指向了集合的末尾,遍历过程即结束。
利用 Iterator 接口以及 List 中的 iterator 方法,可以对整个 List 进行遍历。
public class TestArrayList { public static void main(String args[]){ List list = new ArrayList(); list.add("hello"); list.add("world"); list.add("java"); list.add("study"); Iterator iter = list.iterator(); while(iter.hasNext()){ Object value = iter.next(); System.out.println(value); } } }
迭代遍历往往是用 while 循环来实现的。利用 hasNext 方法返回值作为循环条件,判断List 后面是否还有其他元素。在循环体中,调用 next 方法,一方面把迭代器向后移动,另外一方面一一返回 List 中元素的值。
4.3 实现类
List 接口有以下几个实现类。要注意的是,这几个类都实现了 List 接口,也就是说,如果我们针对 List 接口编程的话,使用不同的实现类,编程的方式是一样的。例如,ArrayList和 LinkedList 都实现了 List 接口,如果我们要把上一小节的程序里的实现由 ArrayList 替换成 LinkedList,只需要把这一句代码:
List list = new ArrayList();
改为
List list = new LinkedList();
其余代码由于都是针对 List 接口的,因此完全不需要修改。也就是说,不管实现类是什么样子,对 List 接口的操作是一样的。这也从一个侧面反映了接口的作用:解耦合。
4.3.1 ArrayList 和 LinkedList
1,ArrayList 的特点是采用数组实现。
用数组这样一种结构来实现 List 接口,具有以下特点:
用数组实现 List 接口,如果要查询 List 中给定下标的元素,只需要使用数组下标就可以直接查到,实现起来非常方便,而且由于数组中,元素的存储空间是连续的,因此通过下标很容易快速对元素进行定位,因此查询效率也很高。
2,LinkedList 实现 List 接口时,采用的是链表的实现方式。
最基本的链表结构是这样的:链表由多个节点组成。每个节点分为两个部分:第一个部分用来储存链表的数据,另一个部分用来储存下一个节点的地址。
List list = new LinkedList(); list.add("hello"); list.add("world"); list.add("java"); list.add("study");
在查询方面,相对于数组直接使用下标,链表实现的 LinkedList,在查询方面效率较低。
相对使用数组实现 List,使用链表实现 List 中的插入和删除功能,由于没有数组扩容以及移动数据等问题,因此效率要远远高于使用数组实现。
4.3.2 Vector
Vector 同样实现了 List 接口,而且也是使用数组实现。
这两个类实现的方式都采用数组实现,所不同的是,Vector 为了保证线程安全,采用了重量级的实现方式。在 Vector 中,所有的方法都被设计为了同步方法。这样,当多线程共同访问同一个 Vector 对象时,不会产生同步问题,但却牺牲了访问的效率。而 ArrayList 中所有方法并没有被作成同步方法,因此访问效率较快。当然,当多线程同时访问同一个 ArrayList 对象时,可能会造成线程的同步问题。