Java集合系列之总体框架

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lkp1603645756/article/details/84988573

前言:在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集合,集合就是将若干性质相同或相近的类对象组合在一起而形成的一个整体 。

Java集合是java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、数组、映射等。

Java集合工具包位置是java.util.*

Java集合主要可以划分为5个部分:

  • List列表
  • Set集合
  • Queue队列
  • Map映射
  • 工具类 (Iterator迭代器、Enumeration枚举类、Arrays和Collections)

下面我用一幅图来表示

其中淡绿色的表示接口,红色的表示我们经常使用的类。

1、基本概述

看上面的框架图,先抓住它的主干,即Collection和Map。

1)Collection:一个独立元素的序列,这些元素都服从一条或者多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)

2)Map:一组成对的“键值对”对象,允许你使用键来查找值。

两个概念下的各个实现类:

|Collection 
|  ├List 
|  │-├LinkedList 
|  │-├ArrayList 
|  │-└Vector 
|  │ └Stack 
|  ├Set 
|  │-└HashSet
|  │ └LinkedHashSet 
|  │-└TreeSet 
|  ├Queue

|Map 
  ├ Hashtable 
  ├ HashMap
  │  └ LinkedHashMap
  ├ TreeMap
  └ WeakHashMap

2、Collection

Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作和属性,它必须继承java.lang.Iterable接口。

Collection 接口来源于Java.util包,是非常实用常用的数据结构,字面意思就是容器。
其父接口:Iterable
其子接口:List,Set,Queue等。

Collection的方法:

boolean add(Object o)   添加对象到集合
boolean remove(Object o)   删除指定的对象
int size()   返回当前集合中元素的数量
boolean contains(Object o)   查找集合中是否有指定的对象
boolean isEmpty()   判断集合是否为空
Iterator iterator()   返回一个迭代器
boolean containsAll(Collection c)   查找集合中是否有集合c中的元素
boolean addAll(Collection c)   将集合c中所有的元素添加给该集合
void clear()   删除集合中所有元素
void removeAll(Collection c)   从集合中删除c集合中也有的元素
void retainAll(Collection c)   从集合中删除集合c中不包含的元素

 

3、List

List承诺可以将元素维护在特定的序列中。List接口在Collection的基础上加入了大量的方法,使得可以在List中间可以插入和移除元素。

下面介绍List的实现类:

3.1:ArrayList

ArrayList是实现了基于动态数组的数据结构,它的优点在于随机访问元素快,但是在中间插入和移除比较慢。

3.2:LinkedList

LinkedList基于链表的数据结构,它的优点在于新增和删除元素操作。通过代价较低在List中间进行插入和移除,提供了优化的顺序访问,但是在随机访问方面相对较慢。但是他的特性功能要比ArrayList强大的多,支持Queue和Stack。LinkedList存储的时候它的物理地址不一定是连续的。

3.3:Vector 
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个 Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例 如,添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException,因此必须捕获该 异常。

2.3.2:Stack  
“栈”通常是指“后进先出”(LIFO)的容器。Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方 法,还有 peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

4、Set

Set也是一个集合,但是他的特点是不可以有重复的对象,所以Set最常用的就是测试归属性,很容易的询问出某个对象是否存在Set中。并且Set是具有和Collection完全一样的接口,没有额外的功能,只是表现的行为不同。

4.1:HashSet

HashSet查询速度比较快,但是存储的元素是随机的并没有排序

4.1.2:LinkedHashSet

LinkedHashSet继承自HashSet,源码更少、更简单,唯一的区别是LinkedHashSet内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的。

4.2:TreeSet

TreeSet是将元素存储红-黑树结构中,所以存储的结果是有顺序的(所以如果你想要自己存储的集合有顺序那么选择TreeSet)

5、Queue

Queue是队列,队列是典型的先进先出(FIFO)的容器,就是从容器的一端放入元素,从另一端取出,并且元素放入容器的顺序和取出的顺序是相同的。LinkedList提供了对Queue的实现,LinkedList向上转型为Queue。其中Queue有offer、peek、element、pool、remove等方法

Queue的方法:

boolean add(E e)   将指定的元素插入到此队列中,如果可以立即执行此操作,而不会违反容量限制, true在成功后返回 IllegalStateException如果当前没有可用空间,则抛出IllegalStateException。  
E element()   检索,但不删除,这个队列的头。  
boolean offer(E e)   如果在不违反容量限制的情况下立即执行,则将指定的元素插入到此队列中。  
E peek()   检索但不删除此队列的头,如果此队列为空,则返回 null 。  
E poll()   检索并删除此队列的头,如果此队列为空,则返回 null 。  
E remove()   检索并删除此队列的头。  

Queue有两个常用的实现类:LinkedList和PriorityQueue,下面分别介绍一下PriorityQueue这个类。

5.1:PriorityQueue

PriorityQueue是一个比较标准的队列实现类,之所以说它是比较标准的队列实现,而不是绝对标准的队列实现是因为:PriorityQueue保存队列元素的顺序并不是按加入队列的顺序,而是按队列元素的大小进行重新排序。因此当调用peek方法活着pull方法来取出队列中的元素时,并不是取出最先进入队列的元素,而是取出队列中最小的元素。从这个意义上看,PriorityQueue已经违反了队列的最基本原则:先进先出(FIFO)。

6、Map

Map在实际开发中使用非常广,特别是HashMap,想象一下我们要保存一个对象中某些元素的值,如果我们在创建一个对象显得有点麻烦,这个时候我们就可以用上map了,HashMap采用是散列函数所以查询的效率是比较高的,如果我们需要一个有序的我们就可以考虑使用TreeMap。这里主要介绍一下HashMap的方法,大家注意HashMap的键可以是null,而且键值不可以重复,如果重复了以后就会对第一个进行键值进行覆盖。

6.1:Hashtable

Hashtable继承Map接口,实现一个key-value映射的哈希表,它其中的方法是同步的。任何非空(non-null)的对象都可作为key或者value。**添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。

6.2:HashMap

HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。 

6.2.2:LinkedHashMap

大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,因为有些场景,我们期待一个有序的Map。

这个时候,LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序LinkedHashMap的Key和Value都允许空,它的Key重复会覆盖、Value允许重复,它是有序的,非线程安全

6.3:WeakHashMap

WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

7、Iterator和Foreach

现在foreach语法主要作用于数组,但是他也可以应用于所有的Collection对象。Collection之所以能够使用foreach是由于继承了Iterator这个接口。

8、Collections和Arrays

Collections是个java.util下的类,它包含有各种有关集合操作的静态方法。他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

Arrays是专门用来操作数组(array),提供搜索、排序、复制等静态方法。

      equals():比较两个array是否相等。array拥有相同元素个数,且所有对应元素两两相等。

      sort():用来对array进行排序。

      binarySearch():在排好序的array中寻找元素。

9、总结:

1):数组是将数字和对象联系起来,它保存明确的对象,查询对象时候不需要对查询结果进行转换,它可以是多维的,可以保存基本类型的数据,但是数组一旦生成,其容量不能改变。所以数组是不可以直接删除和添加元素。

2):Collection保存单一的元素,而Map保存相关联的值键对,有了Java泛型,可以指定容器存放对象类型,不会将错误类型的对象放在容器中,取元素时候也不需要转型。而且Collection和Map都可以自动调整其尺寸。容器不可以持有基本类型。

3):像数组一样,List也建立数字索性和对象的关联,因此,数组和List都是排好序的容器,List可以自动扩容

4):如果需要大量的随机访问就要使用ArrayList,如果要经常从中间插入和删除就要使用LinkedList。

5):各种Queue和Stack由LinkedList支持

6):Map是一种将对象(而非数字)与对象相关联的设计。HashMap用于快速访问,TreeMap保持键始终处于排序状态,所以不如HashMap快,而LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问的能力

7):Set不接受重复的元素,HashSet提供最快的访问能力,TreeSet保持元素排序状态,LinkedHashSet以插入顺序保存元素。

8):新程序中不应该使用过时的Vector、Hashtable和Stack

一般情况下会碰到的接口和类

其实只有四种容器:Map、List、Set和Queue(Queue的java.util.concurrent实现没有包括在上面这张图中),它们各有两到三个实现版本。

1、常用的容器用黑色粗线框表示。

2、点线框表示接口,实现框表示普通的(具体的)类。

3、带有空心箭头的点线表示一个特定的类实现了一个接口。

4、实心箭头表示某个类可以生成箭头所指向类的对象。

例如,任意的Collection可以生成Iterator,而List可以生成ListIterator(也能生成普通的Iterator,因为List继承自Collection)

猜你喜欢

转载自blog.csdn.net/lkp1603645756/article/details/84988573