JAVA集合--Collection

来源:互联网 发布:seo课程seo8o 编辑:程序博客网 时间:2024/06/06 17:20

集合概述

java集合就像一种容器,我们可以把多个对象丢进该容器中。在编程时,我们需要存放多个数据,当然我们可以使用数组来保存多个对象,但是数组的长度不可变化,且无法保存具有映射关系的数据。集合类主要负责保存,盛装其他数据,因此集合类也被成为容器类。

集合类和数组不一样,数组即可以保存基本类型,也可也保存对象;而集合里保存的只能是对象。java的集合类主要由两个接口派生而出:Collection和Map。

Collection

Collection继承树

collection有3个派生出来的子接口,分别是Set、Queue和List。Set与List接口分别代表了无序集合与有序集合。Queue时java提供的队列的实现。由于Collection是父接口,所以该接口定义的方法可同时用于Set、List和Queue。详细方法请查询JAVA API。

Tips1:当使用println方法来输出集合对象时,将输出[a,b,c,…..]形式,因为Collection实现类都重写了toString()方法,该方法可以一次性输出集合中的所有元素。

关于Collection遍历的通用方法:

Iterator迭代器

Iterator接口也是Java集合框架的成员,但是它与Collection与Map的集合不一样,Collection与Map主要用于盛装其他对象,而Iterator主要用于遍历(即迭代访问)Collection中的元素。

Iterator接口定义3个方法,hasNext:如果被迭代的集合元素还没有被遍历返回true、next:返回集合的下一个元素、remove:删除集合里上一次next返回的元素。

//创建一个集合Collection collection = new HashSet();//获取结合对应的迭代器Iterator it = collection.iterator()while(it.hasNext()){    //tips:next()方法返回Object类型,需进行类型转换    String string = (String)it.next();    //从集合中删除上一次next方法返回的元素    it.remove();}

若上述代码对变量string进行赋值,当再次遍历集合时,集合里的值不会发生改变。因为Iterator对集合进行迭代时,并不把元素本身传给了迭代变量,而是把集合元素的值给了迭代变量,所以修改迭代变量对于集合元素本身没有任何影响。

当Iterator迭代访问Collection集合元素时,Collection元素不能被改变,只有通过remove方法删除元素才可以,否则会引发java.util.ConcurrentModificationException异常。Iterator采用了快速失败(fail-fast)机制,一旦在迭代中检测到该集合已经被修改,程序立即引发ConcurrentModificationException异常,这样可以避免资源共享而引发的问题。


Collection中所有Iterator的实现都是按fail-fast来设计的(ConcurrentHashMap和CopyOnWriteArrayList这类并发集合类除外)。
Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent中的集合类都为fail-safe的。Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。


为何Iterator接口没有具体的实现?
Iterator接口定义了遍历集合的方法,但它的实现则是集合实现类的责任。每个能够返回用于遍历的Iterator的集合类都有它自己的Iterator实现内部类。
这就允许集合类去选择迭代器是fail-fast还是fail-safe的。比如,ArrayList迭代器是fail-fast的,而CopyOnWriteArrayList迭代器是fail-safe的。


Tips2:Iterator必须依附于Collection对象,若有一个Iterator对象,则必然有一个与之关联的Collection对象。

foreach遍历

Collection collection = new HashSet();for(Object obj : collection){    //读取集合元素}

foreach循环中的迭代变量也不是元素本身,修改foreach元素中的迭代遍历也没有什么意义。当使用foreach循环迭代集合元素时,该集合也不能被改变,否则也会引发ConcurrentModificationException异常。

Set集合

Set集合中多个对象之间没有明显的顺序,Set集合与Collection集合基本完全一样,没有提供额外的方法,只是不允许包含相同的元素。Set判断两个对象相同不是使用==而是使用equals方法。

HashSet

HashSet使用Hash算法来存储集合中的元素,具有良好的存取和查找性能。特点:

  • 不能够保证元素顺序;
  • HashSet是非同步的;
  • 集合元素值可以为null;

当HashSet集合存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,根据HashCode的值决定对象的存储位置。HashSet通过判断两个对象的equals与hashCode方法,两者都相等才判断为两个元素相等。

那么这里就有两种情况:
(1)equals相同、hashcode不同:当两个元素通过equals方法返回true但HashCode值不等,HashSet可以把它们添加在不同的位置。但这就与Set集合的规则有出入了。
(2)hashcode相同,equals不同:因为两个对象的hashcode值相同,HashSet将它们保存在同一位置,使用链式结构保存,而HashSet根据hashcode快速定位查找元素,两个对象拥有相同的hashcode会导致性能下降。

LinkedHashSet

LinkedHashSet是HashSet的子类,LinkedHashSet也是根据HashCode定位元素的存储位置,但它使用链表来维护元素次序。LinkedHashSet需要维护元素的插入顺序,性能略低于HashSet,但是在迭代全部元素时,拥有良好的性能,因为内部元素有序。

TreeSet

TreeSet是SortedSet的实现类,TreeSet可以确保元素处于排序状态。TreeSet采用红黑树的数据结构来存储集合元素。相比HashSet它提供了一些额外的与排序有关的方法。因为TreeSet是有序的,所以增加了访问第一个,前一个、后一个、最后一个元素的方法。

  • 自然排序
    TreeSet会调用集合元素的compareTo方法比较元素大小,按元素升序排列,这就是自然排序。
    Java提供了一个Compare的接口,该接口定义了一个compareTo(Object obj)的方法,该方法返回一个整数值,0:两个对象相等;正整数:obj1大于obj2,;负整数:obj1小于obj2.

    obj1.compareTo(obj2);

Tips3:如果把一个对象添加到TreeSet,该对象必须实现Comparable接口,否则程序会抛出异常

  • 定制排序
    如果需要集合的元素按照自定义的顺序排序,则需要通过Compatator接口,在创建TreeSet时创建一个匿名内部类对象,该对象负责元素的排序逻辑。
TreeSet treeSet = new TreeSet(new Comparator() {    @Override    public int compare(Object o1, Object o2) {        // TODO Auto-generated method stub        return 0;    }});

EnumSet

EnumSet是一个专为枚举类设计的集合类,EnumSet中所有的元素都必须是指定枚举类的枚举值。EnumSet在内部以位向量的形式存储,这种存储形式紧凑高效。EnumSet也不允许加入null元素。

各Set实现类的性能分析

HashSet与TreeSet是Set的两个典型实现。HashSet的性能总是比TreeSet好,特别是常用的添加与查询操作,只有当需要一个Set有序时,才使用TreeSet,否则都应该使用HashSet。
LinkedHashSet对于普通的插入和删除操作要比HashSet稍微慢一点,但是由于有了链表,LinkedHashSet的遍历会更快。
EnumSet是所有Set实现类中性能最好的。
Tips4:HashSet、TreeSet、EnumSet与LinkedHashSet都是县城不安全的。

List集合

List是一个可重复、有序的集合,集合中每个元素都有其对应的顺序索引。List作为Collection的子接口,可以使用Collection的全部方法并增加了一个根据索引操作List的方法。List判断两个对象相等是根据equals方法。调用List的remove方法,若集合中有连个相同的对象,总是会删除第一个。

List还额外提供了一个ListIterator()方法,该方法继承了Iterator接口,专门操作List。ListIterator在Iterator的基础上增加了返回上一个元素与插入等相关方法。

Arrarys工具类中提供了一个能将数组或者指定数量对象转化为List集合的方法:asList()。

ArraryList与Vector

ArraryList与Vector都实现了List类,使用initialCapacity参数来设置该数组的长度,当向ArraryList与Vector中添加元素超出了该数组长度时,initialCapacity会自动增加。对于通常的场景,无需关心ArraryList与Vector的initialCapacity,但如果向ArraryList与Vector中添加大量元素时,可使用ensureCapacity(int minCapacity)方法一次行的增加initialCapacity,减少分配次数,提高性能。如果创建空的ArraryList与Vector时不指定initialCapacity参数,则数组长度默认为0。

ArraryList与Vector相比,ArraryList是线程不安全的。

Vector还提供了stack的子类,但是一般较少使用,一般使用LinkedList替代。

Queue集合

Queue用于模拟队列数据结构,先进先出FIFO。

PriorityQueue

PriorityQueue是Queue的一个实现类。PriorityQueue保存队列元素顺序并不是按照加入队列的顺序,而是按照队列元素大小进行重新排序的。所以PriorityQueue不允许插入null元素。它对于队列元素的要求基本与TreeSet一致。

Deque与ArraryDeque

Deque是Queue的子接口,它代表一个双向队列。ArraryDeque是它的实现类。

LinkedList

LinkedList是一个List接口的实现类,但是它还实现了Deque接口,因此它是一个List集合,也可以被当做双端队列来使用,当然模拟栈也可以。
LinkedList的实现机制与ArraryList、ArraryDeque完全不同,ArraryList、ArraryDeque使用数组来保存集合中的元素,因此拥有较好的随机访问性能;LinkedList使用链表实现,在删除与插入时性能优秀。

各线性表性能分析

类型 实现机制 随机访问排名 迭代操作排名 插入操作排名 删除操作排名 数组 连续内存区保存元素 1 不支持 不支持 不支持 ArraryList/ArraryDeque 以数组保存元素 2 2 2 2 Vector 以数组保存元素 3 3 3 3 LinkedList 以链表保存元素 4 1 1 1

List使用建议:

  • 如需遍历List元素,对于ArraryList与Vector集合应使用随机访问的方法,LinkedList应采用迭代器的方法来遍历。
  • 需要经常插入与删除的List,应使用LinkedList而不是ArraryList。
  • 如果需多线程使用,应使用Collections进行包装。

Collection的同步控制

Collections类中提供了多个synchronized的方法,这些方法可以将指定的集合包装成为线程安全的集合,解决多线程的安全问题。
这里写图片描述

0 0
原创粉丝点击