Java集合框架及其衍生

1.Set,List,Map的区别和联系。
首先三者都是接口,Set和List是接口Collection的子接口,而Map是一个单独的接口。
List:可以运行重复的对象,可以插入多个Null个元素,是一个有序的容器,保持每个元素的插入顺序,输出的顺序就是插入的顺序。常用的实现类有ArrayList,LinkedList和Vector.ArrayList最为流行。它提供了索引的随意访问。LinkedList则对于经常需要从List中添加或者删除元素的场合比较合适。
Set:不允许重复的对象,一个无序的容器,并且无法保证每个元素的存储顺序,Tree通过一个Comparator或Comparable维护的一个排序顺序,只允许一个Null值,Set接口最流行的实现类是HashSet,LinkedHashSet以及TreeSet最流行的是基于HashMap实现的HashSet,TreeSet还实现了SortedSet接口。
Map:Map的每个Entry都是持有两个对象,一个键一个值,可能会存在相同值对象,但是每一个键对象都是唯一的。Map里可以有很多Null的值对象,但是只能存在一个Null的键对象。TreeMap也通过Comparable或者Comparator维护了一个排序顺序。Map接口最流行的几个实现类分别是HashMap,LinkedHashMap,Hashtable,TreeMap.
大致的结构图如下:(图片来源于网上)
2. Collection接口
Collection接口市处理对象集合的根接口,其中定义了很多元素的操作的方法,Collection接口有三个字接口分别是List,Set,Quene。
Collection接口定义了以下这些方法。
其中比较常用的方法,比如方法add()添加一个元素到集合中,addAll()指定集合的所有元素添加到集合中contains()方法检测几个字是否含有指定元素,toArray()方法返回一个表示集合的数组。另外,Collection中有一个iterator()函数,它的作用是返回一个Iterator接口。我们通常用迭代器来遍历集合。
3.List接口
List接口为Collection直接接口,List所代表的是有序的Collecion。即它用某种特定的插入顺序,来维护元素的顺序,用户可以对列表中的每个元素的插入位置,精准地控制。同时可以根据元素的整数索引访问元素。并搜索列表中的元素,实现的集合有ArrayList,LinkedList,Vector,Stack
3.1ArrayList实现类
ArrayList是一个动态数组,也是我们最经常用的几个。它允许人格规则的元素插入甚至包括null。每一盒ArrayList都有一个初始容量(10),该容量代表了数组的大小,随着容器中的元素不断增加,容器的大小也会随着增加,在每次想容器中增加元素的同时都会进行容量检查,当快溢出的时候,就会进行扩容操作。如果我们明确所插入的元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间,和效率。
当原来的数组不够了,就创建原来1.5倍的数组拷贝到原来的数组中去。1.5倍是扩容因子。
比较常用的成员方法:
Object get(int index)返回此前列表中指定位置的元素。
int indexof(Object o)出现指定元素的次数
3.2LinkedList
ArrayList是一个动态的数组,而LinkedList是一个双向链表。由于实现方式不同,LinkedList不能随机访问。在列表中索引的操作从开头或结尾遍历。这样做的好处就是可以通过较低的代价在List中插入和删除操作。
特殊方法:
addFirst(Object o) addLast(Object o) removeFirst() removeLast
实现同步:
List list = new Collections.synchronized(new LinkedList())
LinkedList它内部封装是双向链表的数据结构,每个结点是一个Node对象,Node对象中封装是三个元素,除了要存储的对象还有指向上一个的元素,以及指向下一个的元素。
ArrayList插入和删除的效率低,LinkedList查询的效率低。
3.3Vector类
与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。他的操作与ArrayList几乎一样。
3.4Stack
Stavk继承自Vector,实现一个后进后出的堆栈,基本的push和pop方法,还有peek方法得到栈顶的元素。empty方法测试堆栈是否为空。search检查一个元素在堆栈中的位置。Stack刚创建是空栈。
4.Set接口
Set是一种不包括重复元素的Collection 无序,即任意两个元素e1和e2都有e1.equal(e2)=false。Set最多有一个null元素。虽然Set元素在set种德位置由该 元素德HashCode决定德。其具体位置其实是固定的。如果对象重写了hashcode和equals方法是相同的话,也是不能放到Set中去。
4.1HashSet类
HashSet是一个没有重复元素的集合。它是由HashMaps实现的,不能保证元素的顺序(这里所说的没有顺序是指:元素插入的顺序与输出顺序不一致),而且HashSet允许使用null元素。HashSet是非同步的,如果多个线程同时访问一个HashDet而其中至善一个线程修改了该Set,那么他必须保持外部同步。HashSet按照Hash算法来存储集合的元素,因此有很好的存取和查找性能。
HashSet的实现方式大致如下,通过一个HashMap存储元素,元素存放在HashMap的key中,而Value统一使用一个Object对象。HashSet按Hash算法来存储集合的元素,因此有很好的存取和查找性能。
注意:HashSet中存放null值,只能最多一个。HashSet虽然是无序的,但是存储的元素的位置是确定的必须操作可变对象。如果一个Set的可变改变自身的状态,导致equal相同将造成一些问题。
4.2LinkedHashSet类
LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。LinkedHashSet集合同样是根据hashcode值来决定元素的存储位置,但是他同时使用链表维护元素的次序。这样使得元素看起来像是插入顺序保存的,也就是说当遍历该集合的时候,LinkedHashSet以元素的添加顺序访问集合的元素。
4.3TreeSet类
TreeSet是一个有序的集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态,TreeSet支持两种排序方式,自然排序和定制排序。其中自然排序的默认的排序方式,当我们构造TreeSet是若使用不带参数的构造函数,则TreeSet的使用比较器,若用户需要使用自定义的比较器,则需要使用比较器的参数。

TreeSet集合不是通过hashcode和equal函数比较元素的,它是通过compare或者compareTo函数判断元素是否相等,compare函数通过判断来那个个对象的id,相同的id判断为重复元素,不会加入到集合中。
5.Map接口
Map与List,Set接口不同,它是由一系列的键值对组合成的集合,提供了key到value的映射。同时也没有继承Collection。在Map中保证了key与value之间一一对应的关系,所以key的值是不可以重复的,value的值是可以重复的。
主要方法:
int size() 返回Map的大小
boolean isEmpty() 判断Map集合是否为空
boolean containskey(Object key) 判断key是否存在
boolean containsvalue(Object value) 判断value是否存在
get(Object key) 获取元素
void put (key , value)
void remove(Object key)
clear() 从Map中删除所有的映射
putAll(Map t) 指定Map中的所有映射复制到此map
entrySet返回Map中映射的Set视图。Set中的每个元素都是MapEntry对象,可以使用getKey和getValue方法访问后者的键元素和值元素。
keySet返回Map中所包含的Set视图,删除Set中的相应的映射

5.1HashMap类
HashMap类是基于哈希表的Map接口实现并允许使用null键和null值(不同步),它是为了快速查询设计的,其内部定义一个hash表数组(Entry [] table)元素会通过哈希函数将元素的哈希地址转换成数组中存放的索引。如果有冲突,则使用散列表的形式将所有的相同哈希地址的元素串起来,可以通过查看HashMap.Entry的源码它是一个单链表的接口。
当我们创建一个HashMap对象的时候,默认会创建一个长度为16的entry的数组,当每次扩充的时候都会增长到原来的两倍。‘
5.2LinkedHashMap
LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。
      LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
      LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。
      根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。
      注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。
      由于LinkedHashMap需要维护元素的插入顺序,因此性能略低于HashMap的性能,但在迭代访问Map里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。
5.3TreeMap类
TreeMap 是一个有序的key-value集合,非同步,基于红黑树(Red-Black tree)实现,每一个key-value节点作为红黑树的一个节点。TreeMap存储时会进行排序的,会根据key来对key-value键值对进行排序,其中排序方式也是分为两种,一种是自然排序,一种是定制排序,具体取决于使用的构造方法。
自然排序:TreeMap中所有的key必须实现Comparable接口,并且所有的key都应该是同一个类的对象,否则会报ClassCastException异常。
定制排序:定义TreeMap时,创建一个comparator对象,该对象对所有的treeMap中所有的key值进行排序,采用定制排序的时候不需要TreeMap中所有的key必须实现Comparable接口。
TreeMap判断两个元素相等的标准:两个key通过compareTo()方法返回0,则认为这两个key相等。
如果使用自定义的类来作为TreeMap中的key值,且想让TreeMap能够良好的工作,则必须重写自定义类中的equals()方法,TreeMap中判断相等的标准是:两个key通过equals()方法返回为true,并且通过compareTo()方法比较应该返回为0。
5.4HashTable 是HashMap同步的实现。
两者的区别:HashTable是基于陈旧的Dictionary类的,HashMap是Java1.2引进的Map接口的一个实现。HashTable是同步的的,就是线程安全的。而HashMap是不同步的,线程不安全的。HashMap可以为空,但是HashTable是不能为空的,继承的基类不同。以及支持遍历的种类不同,HashMap只支持Iterator(迭代器)遍历。而HashTable支持Iterator和Enumeration(枚举器)两种遍历方式。
6.集合框架扩展部分
6.1迭代器(Iterator)
Iterator是一个接口,它是结合的迭代器。集合可以通过Tierator去遍历集合中的元素。
提供了三个方法
boolean hasNext():判断集合是否存在下一个元素。如果有,hasNext()方法返回true
Object next();返回集合下一个元素。
void remove() 删除集合里上一次next方法返回的元素
eg:
public class IteratorExample { public static void main(String[] args) { ArrayList<String> a = new ArrayList<String>(); a.add("aaa"); a.add("bbb"); a.add("ccc"); System.out.println("Before iterate : " + a); Iterator<String> it = a.iterator(); while (it.hasNext()) { String t = it.next(); if ("bbb".equals(t)) { it.remove(); } } System.out.println("After iterate : " + a); }}
Iterator只能单向移动,Iterator.remove()是唯一安全的方式来在迭代过程中修改集合remove()方法只能被调用一次,如果违反这个规则将抛出一个异常。
在java1.5以后对for循环增强了,可以通过增强for循环直接遍历我们的集合,但是在数据比较大的时候,我们增强For循环的性能比迭代器的遍历的性能要差一点。Map集合中EntrySet以及KeySet都是得到Map映射的Set视图,EntrySet的遍历要比KeySet的性能要好一点。

再介绍一个ListIterator,个人觉得是Iterator的升级版
(1)ListIterator有add()方法,可以向List中添加对象,而Iterator不能
(2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
(3)ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。

6.2Collections是一个工具类,主要包含了一些静态多态的方法
方法如下:
void reverse(List list) 反转
void shuffle(List list) 随机排序
void sort(List list) 按自然排序的升序排序
void sort( List list,Comparator c)定制排序,由Comparator控制排序逻辑
void swap(List list,int i,int j)交换两个索引位置的元素
int binarySearch(List list,Object key) 二分法查找 返回下标
int max(Collection coll)根据元素的自然排序,返回索引。
int max(Collection coll,Comparator c)根据定制排序,返回最大元素。
void fill (List list,Object obj)用元素obl 填充list所有元素
int frequency(Collection c ,Object obj)统计元素出现的次数
boolean replaceAll(List list ,Object Oldval,Object Newval)替换旧元素。
Collection c = Collections.synchronizedCollection(new ArrayList()); 返回线程安全的集合。
Collections提供了三类方法返回一个不可变集合,
emptyXXX(),返回一个空的只读集合(这不知用意何在?)
singleXXX(),返回一个只包含指定对象,只有一个元素,只读的集合。
unmodifiablleXXX(),返回指定集合对象的只读视图。

6.3那些集合类是线程安全的?
vector stack hashTable enumeration

6.4什么时候使用HashMap,LinkedHashMap,ConcurrentHashMap,WeakHashMap
ConcurrentHashMap是使用了锁分段技术来保证线程安全的,锁分段技术,首先将数据分成一段一段的储存。然后给每一段数据配置一把锁。当以和线程占用锁访问其中一段数据的时候,其他短的数据也能被其他线程访问,所以ConcurrentHashMap是在每个段(segiment)中线程安全的。(改实例在java1.7和java1.8之间还是有很大的不同的,具体到后面可以分享一下源码)
LinkedHashMap维护一个双链表,可以将里面的数据按写入的顺序读出。
WeakHashMap继承于AbstractMap实现了Map接口,和HashMap一样,WeakHashMap也是一个散列表,它存储的内容也是键值映射,而且键和值都是可以是Null的,不过WeakHashMap的键是弱键,在过程当WeakHashMap中被自动移除。更准确的对于给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止,被终止,然后被回收,某个键值也就从映射关系中有效移除了。
6.5什么时候使用CopyOnWruteArrayList
CopyOnWrtieArrayList(写数组的拷贝)使ArrayList的一个线程安全的变体,CopyOnWriteList和CopyOnWriteSet都是线程安全的集合,其中可变的操作都是通过底层数组进行一次新的复制来实现的。它绝对不会抛出Concurrent这类的异常,因为该列表在编程不会做任何的修改CopyOnWriteArrayList适合用在读多,写少的并发应用中,它适合在读操作远远大于写操作的场景里。比如缓存,它不存在扩容的概念,每次写操作add or remove都要copy一个副本,在副本的基础上修改后改变array的引用,所以称为CopyOnWrite因此在写操作使加锁,并且对整个listCopy操作相当耗时,过多写操作不推荐使用该存储结构。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值