java高级特性:集合框架

来源:互联网 发布:李杰灵的淘宝店 编辑:程序博客网 时间:2024/05/17 01:55

数组和集合的区别

  1. 数组可以存储基本数据类型和对象,集合中只能存储对象,(可以以包装类的形式存储基本数据类型)。
  2. 数组长度固定,集合长度可以动态改变。
  3. 定义数组必须指定数组的元素类型,集合默认的所有元素都是Object。
  4. 无法直接获取实际存储的元素个数,length用来获取数组长度,而集合框架中size()方法可以直接获取数组是急的元素个数。
  5. 数组采用分配连续空间的方式,集合有多种实现方式和不同的适用场合。
  6. 集合采用了接口和类的形式,具有继承、封装、多态的特性,考法效率较数组更高。
  7. 数组提供了Arrays类提供对数组的一系列操作,而集合提供了Collections类来操作集合。

先来两张集合图来镇博哈~~

集合框架概述
集合框架体系图

集合框图


由易到难,由浅入深,java集合框架需要学习的还有很多,随时补充。

java集合框架是一种统一的标准体系结构。
集合框架包含三大体系内容:

  1. 对外的接口
  2. 接口的实现
  3. 对集合运算的算法

接口:表示集合的抽象数据类型,例如:Collection、List、Set、Map、Iterator
实现:集合框架中对接口的具体实现:例如:ArrayList、LinkedList、HashSet、HashMap
算法:对某个集合完成有用的计算方法。JAVA提供了进行集合操作的工具类Collections。类似于Arrays类。


从框架图中不难看出,java集合框架有两大接口:CollectionMap
其中Collection又有两个子接口:ListSet
所以java集合框架共有三大接口:List、Set、Map

具体介绍:

这里写图片描述

Collection:允许重复、无序的对象

List:允许重复、有序(以元素插入的次序来放置元素)的对象
Set:不允许重复、无序的对象

Map:存储成对的键 - 值 对象,提供key到value的映射
key无序,不可重复;value无序,可以重复


具体实现类和方法:

Collection接口方法

size() - 集合内的对象数量

add(E)/addAll(Collection) - 向集合内添加单个/批量对象

remove(Object)/removeAll(Collection) - 从集合内删除单个/批量对象

contains(Object)/containsAll(Collection) - 判断集合中是否存在某个/某些对象

toArray()- 返回包含集合内所有对象的数组

List接口增加的方法:

get(int) - 返回指定index位置上的对象

add(E)/add(int, E) - 在List末尾/指定index位置上插入一个对象

set(int, E) - 替换置于List指定index位置上的对象

indexOf(Object) - 返回指定对象在List中的index位置

subList(int,int) -返回指定起始index到终止index的子List对象

常用类ArrayList:

ArrayList基于数组来实现集合的功能,其内部维护了一个可变长的对象数组,集合内所有对象存储于这个数组中,并实现该数组长度的动态伸缩
ArrayList使用数组拷贝来实现指定位置的插入和删除:

这里写图片描述
这里写图片描述
常用类LinkedList:
LinkedList基于链表来实现集合的功能,其实现了静态类Node,集合中的每个对象都由一个Node保存,每个Node都拥有到自己的前一个和后一个Node的引用
这里写图片描述

ArrayList VS LinkedList

  1. ArrayList的随机访问更高,基于数组实现的ArrayList可直接定位到目标对象, 而LinkedList需要从头Node或尾Node开始向后/向前遍历若干次才能定位到目标对象。

  2. LinkedList在头/尾节点执行插入/删除操作的效率比ArrayList要高。

  3. 由于ArrayList每次扩容的容量是当前的1.5倍,所以LinkedList所占的内存空间要更小一些。

  4. 二者的遍历效率接近,但需要注意,遍历LinkedList时应用iterator方式,不要用get(int)方式,否则效率会很低

Arraylist:

优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。

LinkedList:

优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。

适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。

http://mp.weixin.qq.com/s/nrfFY7A9__PJmc75Y_exZg
这篇文章也很清楚的及介绍了两者异同。


Set接口常用类HashSet:
特点:查找效率高
常用方法:

添加元素:
hashset.add(E e):返回boolean型,如果此 set 中尚未包含指定元素,则添加指定元素;如果此 set 已包含该元素,则该调用不更改 set 并返回 false。
删除元素:
hashset.clear():从此 set 中移除所有元素。
hashset.remove(Object o):如果指定元素存在于此 set 中,则将其移除。
hashset.isEmpty():如果此set 不包含任何元素,则返回true。
hashset.contains(Object o):如果此 set 包含指定元素,则返回 true。
hashset.size():返回此 set 中的元素的数量(set 的容量)。

Set接口还有TreeSet和LinkedHashSet需要了解:

TreeSet:

为快速查找设计的Set。底层为树结构,使用它可以从Set中提取有序的序列。

LinkedHashSet:

具有HashSet的查询速度,企且内部使用了链表维护维护元素的顺序(插入的次序)。于是在迭代器遍历Set时,结果会按元素的插入次序来排序显示。

HashSet与Treeset的适用场景

  1. TreeSet 是二叉树(红黑树的树据结构)实现的,Treeset中的数据是自动排好序的,不允许放入null值
  2. HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束
  3. HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。

适用场景分析:

HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

Map接口:
键值对的存储形式的优点是查询指定元素的效率高
Map接口在Collection的基础上,为其中的每个对象指定了一个key,并使用Entry保存每个key-value对,以实现通过key快速定位到对象(value)。Map接口的主要方法包括:

  1. size() - 集合内的对象数量
  2. put(K,V)/putAll(Map) - 向Map内添加单个/批量对象
  3. get(K) - 返回Key对应的对象
  4. remove(K) - 删除Key对应的对象
  5. keySet() - 返回包含Map中所有key的Set
  6. values() - 返回包含Map中所有value的Collection
  7. entrySet() - 返回包含Map中所有key-value对的EntrySet
  8. containsKey(K)/containsValue(V) - 判断Map中是否存在指定key/value

常用类HashMap增加了isEmpty()、clear()方法
isEmpty()若不存在键值对关系,则返回true
clear()清除所有映射关系

Map中还有许多类需要了解和知道:
LinkedHshMap:

类似于HashMap,但是迭代遍历时,取得的键值对的顺序是其插入的顺序,或者最近最少使用的次序,纸币HashMap慢一点,而在迭代遍历时发生更快,因为他是链表维护结构。

TreeMap

:基于红黑树数据结构的实现,查看键或者键值对时,他们会被排序。TreeMap的特点在于,得到的结果是经过排序后的,TreeMap是唯一带有subMap()方法的Map,他可以返回一个子树。

WeakHashMap:

弱键Map,Map中使用的对象被允许释放,这是为解决特殊问题而设计的。如果没有map之外的引用指向某一个键时,则此键会被GC回收。

IdentifyHashMap:

使用==代替equals对键做比较的hashmap。专为解决特殊问题设计。


HashMap和Hashtable的异同

常见面试题。
相同点:

HashMap类出现以前,JDK存在着一个和它同样采用哈希表存储方式,同样实现键值对的集合类HashTable。两者实现原理相同。都使用哈希表来存储键值对。

不同点:

Hashtable继承自Dictionary类,而HashMap实现了Map接口。
Hashtable是线程安全的,HashMap注重速度,但是是非线程安全的。
Hashtable的key和value不允许null值,HashMap都允许null值。
Hashtable是过时的类,开发中最好使用HashMap。

http://mp.weixin.qq.com/s/wnvpPOQvCgE5vgdnoMpGYw
上面的文章具体的说明了他们的异同。

HashMap与TreeMap、HashTable的区别及适用场景

HashMap 非线程安全
HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。
TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。

适用场景分析:

HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。
HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。 HashMap允许空键值,而HashTable不允许。
HashMap:适用于Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。

List、Set、Map的区别以及使用场景
1. List,Set都是继承自Collection接口,Map则不是
2. List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
3. Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
4. Map适合储存键值对的数据
5. 线程安全集合类与非线程安全集合类 :
LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;
HashMap是非线程安全的,HashTable是线程安全的;
StringBuilder是非线程安全的,StringBuffer是线程安全的。


迭代器iterator
iterator专门为集合框架而生
Collection接口的iterator()方法返回一个iterator,然后通过iterator的两个方法即可方便实现遍历

  1. hashNext()判断是否存在另一个可访问的元素。
  2. next()返回要访问的下一个元素。

    遍历Map推荐方法:

        for(Map.Entry<String, String>entry:dogs.entrySet()){            System.out.println(entry.getKey()+"  \t"+entry.getValue());        }   

遍历List方法:

        Iterator<Dog> it=dogs.iterator();        while(it.hasNext()){            Dog dog=  it.next();            System.out.println(dog.getName()+"  \t"+dog.getStrain());        }

遍历Set方法:

        Iterator<Dog> dogit=dogs.iterator();        while(dogit.hasNext()){            Dog dog=dogit.next();            System.out.println(dog.getName()+"  \t"+dog.getStrain());        }