JAVA集合类型详解

集合类简介
数组是很常用的一种数据结构,我们用它可以满足很多的功能,但是,有时我们会遇到如下这样的问题:

1. 我们需要该容器的长度是不确定的。
2. 我们需要它能自动排序。
3. 我们需要存储以键值对方式存在的数据。

如果遇到上述的情况,数组是很难满足需求的,接下来介绍的另一种与数组类似的数据结构——集合类,集合类在Java中由很重要的意义,保存临时数据,管理对象,泛型,Web框架等,很多都大量用到了集合类。

集合框架(collections framework)

集合代表了一组对象(和数组一样,但数组长度不能变,而集合能)。Java中的集合框架定义了一套规范,用来表示、操作集合,使具体操作与实现细节解耦。

其实说白了,可以把一个集合看成一个微型数据库,操作不外乎”增删改查”四种操作,我们在学习使用一个具体的集合类时,需要把这四个操作的时空复杂度弄清楚了,基本上就可以说掌握这个类了。

(1)collection接口主要定义了一些操作集合元素的方法:

1. boolean add()

2. boolean addAll()

3. void clear()

4. boolean contains()

5. boolean containsAll()

6. boolean equals()

7. int hashCode()

(2)Collection使用Iterator接口遍历几何元素

Iterator接口隐藏了各种Collection实现类的细节,向引用程序提供了遍历Collection集合元素的统一编程接口。Iterator接口里定义了如下三个方法:

Boolean hashNext():如果被迭代的集合元素还没有被遍历,则返回true。

Object next():返回集合里的下一个元素。

Void remove():删除集合里上一次next方法返回的元素。

注意:当使用Iterator迭代访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过Iterator的remove方法删除上一次next方法返回的集合元素才可以;否则将引发java.util.Concurrent ModificationException异常。

两大基类Collection与Map

在集合框架的类继承体系中,最顶层有两个接口:

1. Collection表示一组纯数据
2. Map表示一组key-value对

一般继承自Collection或Map的集合类,会提供两个”标准”的构造函数:

1. 没有参数的构造函数,创建一个空的集合类
2. 有一个类型与基类(Collection或Map)相同的构造函数,创建一个与给定参数具有相同元素的集合类

因为接口中不能包含构造函数,所以上面这两个构造函数的约定并不是强制性的,但是在目前的集合框架中,所有继承自Collection或Map的子类都遵循这一约定。

Collection

这里写图片描述
如上图所示,Collection类主要有三个接口:

1. Set表示不允许有重复元素的集合
2. List表示允许有重复元素的集合
3. Queue JDK1.5新增,与上面连个集合类主要的区分是在于Queue主要用于存储数据,而不是处理数据。

List:有序列表,允许存放重复的元素

List集合代表一个元素有序,可重复的集合,集合中每个元素都有对应的顺序索引。List接口中增加了一些根据索引操作元素的方法:

void add(int index,E element):在列表的指定位置插入该元素。

boolean addAll(int index,Collection c):将集合c包含的所有元素都插入到List集合的index处。

Object get(int index):返回集合index索引处的元素。

**ListIterator接口:**List额外提供的一个listIterator()方法,提供了专门操作List的方法。

ListIterator接口在Iterator的基础上增加了如下方法:

boolean hasPrevious():返回该迭代器关联的集合是否还有上一个元素。

Object previous():返回该迭代器的上一个元素。

void add(E e):在指定位置插入一个元素。

实现类:

1. ArrayList:数组实现,需要一块连续的存储空间,查询块,增删慢,不同步,线程不安全,轻量级;

2. LinkedList:链表实现,增删快,查询慢;

3. Vector:数组实现,同步,线程安全,重量级;比较古老,方法名比较长,最好是不使用。

Vector : 基于Array的List,其实就是封装了Array所不具备的一些功能方便我们使用,它不可能走出Array的限制。性能也就不可能超越Array。所以在可能的情况下,我们要多运用Array。另外很重要的一点就是Vector是”synchronized”的。这也是Vector和ArrayList的唯一的区别。

ArrayList:同Vector一样是一个基于Array上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector优越一些,但是当运行到多线程的环境中时,可需要自己在管理线程的同步问题。

LinkedList:LinkList不同于前面两种List,它不是基于Array的,所以不受Array性能的限制。它每一个节点(Node)都包含两方面的内容:1. 节点本身的数据(data);2. 以一个节点的信息(nextNode)。所以当对LinkList做添加,删除动作的时候就不用像基于Array的List一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了。这就是LinkedList的优势。

LinkedList实现了List接口和Deque接口,因此他是一个List集合还可以被当成双端队列来使用。

Queue集合

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

Queue接口定义的方法如下:

boolean add(E e):将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回true,如果当前没有可用的空间,则抛出IllegalStateException。

E element():获取队列头部元素,但不删除该元素。

boolean offer(E e):将指定的元素插入此队列,当使用有容量限制的队列时,此方法通常要优于add(E)。

E peek():获取但不移除此队列的头;如果此队列为空,则返回null。

E pool():获取并移除此队列的头;如果此队列为空,则返回null。

E remove():获取并移除此队列的头。

实现类:

1. PriorityQueue

PriorityQueue是一个比较标准的队列实现类,之所以说比较标准,而不是绝对标准,是因为PriorityQueue保存队列元素的顺序并不是按加入队列的顺序,而是按队列元素的大小进行重新排序。

2.Deque接口与ArrayQueue实现类

Deque接口是Queue接口的子接口,它代表一个双端队列,Deque接口里定义了一些双端队列的方法,允许从两端来操作队列的元素。

Void addFirst(Object e):将指定元素插入该双端队列的开头。

Void addLast(Object e):将指定队列插入该双端队列的末尾。

Iterator descendingIterator():返回该双端队列对应的迭代器,该迭代器将以逆向顺序来迭代队列中的元素。

Object getFirst():获取但不删除队列的第一个元素。

ArrayQueue是Deque接口的典型实现类,他是一个基于数组实现的双端队列,底部也是采用动态的、可重新分配的Object[]数组存储集合元素。

在现在的程序中需要使用”栈”这种数据结构时,推荐使用ArrayDeque或LinkedList,而不是Stack。

Set:无序集合,不允许存放重复的元素

Set集合的方法与Collection基本上完全一样,它没有提供额外的方法。实际上Set就是Collection,只是行为略有不同(Set不允许包含重复元素)。

Set判断两个对象是否相同时根据equals方法。也就是说,只要两个对象用equals方法比较返回false,Set就会接受这两个对象。

实现类:

1. HashSet

HashSet是Set的典型实现,HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。

特点:不能保证元素的排列顺序;不是同步的,不是线程安全;集合值可以是null。

HashSet集合判断两个元素的相等的标准是两个对象通过equals方法比较相等,并且两个对象的HashCode()方法返回值也相等。

2. LinkedHashSet

LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合的时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。

LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

子接口SortedSet,对Set排序实现类:TreeSet

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。

TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0。向TreeSet中添加的应该是同一个类的对象,且最好是不可变对象。

1. 自然排序

自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。

Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。

obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是负数,则表明obj1小于obj2。

如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0。

2. 定制排序

自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现int compare(T o1,T o2)方法,该方法用于比较o1和o2的大小:如果该方法返回正整数,则表示o1大于o2;如果方法返回0,则表示o1等于o2,如果该方法返回负整数,则表示o1小于o2。

如果需要定制排序,则需要在创建TreeSet集合时提供一个Comparator对象与该TreeSet集合关联,由Comparator对象负责几何元素的排序逻辑。

各Set实现类比较

Haset和TreeSer是Set的两个典型实现,HashSet的性能比TreeSet好(特别是最常用的添加,查询元素等操作)只有当需要一个保持排序的Set时,才应该使用TreeSet,否则使用HashSet。

LinkedHashSet:对于普通的插入操作删除,比HashSet慢,遍历会更快。

另外:Set的三个实现类HashSet,TreeSet和EnemSet都是线程不安全的,如果有多个线程访问一个Set集合,则必须手动保持同步:

可用Collections的工具类:例如:

SortedSet s = Collections.synchronizedSortedSet(new TreeSet(…));

Map
这里写图片描述
Map并不是一个真正意义上的集合,但是这个接口提供了三种”集合视角”(collection views),使得可以向操作集合一样操作它们,具体如下:

1. 把map的内容看作key的集合
2. 把map的内容看作value的集合
3. 把map的内容看作key-value映射的集合

实现类:

1. HashMap:键值对,key不能重复,但是value可以重复;key的实现就是HashSet;value对应着放;允许null的key或value;

2. Hashtable : 线程安全的,不允许null的键或值;

3. Properties:key和value都是String类型,用来读配置文件;TreeMap:对key排好序的Map; key 就是TreeSet, value对应每个key; key要实现Comparable接口或TreeMap有自己的构造器;

4. LinkedHashMap:此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。存储的数据是有序的

各Map实现类的性能分析:

1. HashMap与Hashtable的效率大体相同,它们的实现机制几乎一样,HashMap线程不安全,Hashtable线程安全,所以HashMap快一点。

2. TreeMap中所有的key-value对处于有序状态,所以TreeMap比HashMap,Hashtable要慢(尤其是插入、删除),因为TreeMap底层采用红黑树来管理key-value对。

3. LinkedHashMap使用链表维护键值对,所以比HahMap慢一点。

对于一般的·应用场景,推荐使用HashMap。

两个工具类 Arrays 和 Collections

Arrays、此类包含用来操作数组(比如排序和搜索)的各种方法。

Collections、主要提供了在 collection 上进行操作的静态方法(同步集合类方法) 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值