Java集合

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

Java集合主要可以划分为4个部分:List列表、Set集合、Map映射、工具类(Iterator迭代器、Enumeration枚举类、Arrays和Collections)。

Java集合工具包框架如下图。

Java集合

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

Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作和属性。

Collection包含了List和Set两大分支。

(01) List(有序可重复)是一个有序的队列,每一个元素都有它的索引。第一个元素的索引值是0。

List的实现类有LinkedList, ArrayList, Vector, Stack。

(02) Set(无序不可重复)是一个不允许有重复元素的集合。

Set的实现类有HastSet和TreeSet。HashSet依赖于HashMap,它实际上是通过HashMap实现的;TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。

Map是一个映射接口,即key-value键值对。Map中的每一个元素包含“一个key”和“key对应的value”。

AbstractMap是个抽象类,它实现了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是继承于AbstractMap。

Hashtable虽然继承于Dictionary,但它实现了Map接口。

接下来,再看Iterator。它是遍历集合的工具,即我们通常通过Iterator迭代器来遍历集合。我们说Collection依赖于Iterator,是因为Collection的实现类都要实现iterator()函数,返回一个Iterator对象。

ListIterator是专门为遍历List而存在的。

再看Enumeration,它是JDK 1.0引入的抽象类。作用和Iterator一样,也是遍历集合;但是Enumeration的功能要比Iterator少。在上面的框图中,Enumeration只能在Hashtable, Vector, Stack中使用。

最后,看Arrays和Collections。它们是操作数组、集合的两个工具类。

有了上面的整体框架之后,我们接下来对每个类分别进行分析。

Collection架构

下面,我们将对Collection进行概括。下面先看看Collection的一些框架类的关系图:

Collection的一些框架类的关系图

Collection是一个接口,它主要的两个分支是:List 和 Set。

List和Set都是接口,它们继承于Collection。List是有序的队列,List中可以有重复的元素;而Set是数学概念中的集合,Set中没有重复元素!

List和Set都有它们各自的实现类。

为了方便实现,集合中定义了AbstractCollection抽象类,它实现了Collection中的绝大部分函数;这样,在Collection的实现类中,我们就可以通过继承AbstractCollection省去重复编码。AbstractList和AbstractSet都继承于AbstractCollection,具体的List实现类继承于AbstractList,而Set的实现类则继承于AbstractSet。

另外,Collection中有一个iterator()函数,它的作用是返回一个Iterator接口。通常,我们通过Iterator迭代器来遍历集合。ListIterator是List接口所特有的,在List接口中,通过ListIterator()返回一个ListIterator对象。

接下来,我们看看各个接口和抽象类的介绍;然后,再对实现类进行详细的了解。

1. Collection简介

Collection的定义如下:


它是一个接口,是高度抽象出来的集合,它包含了集合的基本操作:添加、删除、清空、遍历(读取)、是否为空、获取大小、是否保护某元素等等。

Collection接口的所有子类(直接子类和间接子类)都必须实现2种构造函数:不带参数的构造函数 和 参数为Collection的构造函数。带参数的构造函数,可以用来转换Collection的类型。


2. List简介

List的定义如下:


List是一个继承于Collection的接口,即List是集合中的一种。List是有序的队列,List中的每一个元素都有一个索引;第一个元素的索引值是0,往后的元素的索引值依次+1。和Set不同,List中允许有重复的元素。 List的官方介绍如下:

A List is a collection which maintains an ordering for its elements. Every element in the List has an index. Each element can thus be accessed by its index, with the first index being zero. Normally, Lists allow duplicate elements, as compared to Sets, where elements have to be unique.

关于API方面。既然List是继承于Collection接口,它自然就包含了Collection中的全部函数接口;由于List是有序队列,它也额外的有自己的API接口。主要有“添加、删除、获取、修改指定位置的元素”、“获取List中的子队列”等。


3. Set简介

Set的定义如下:


Set是一个继承于Collection的接口,即Set也是集合中的一种。Set是没有重复元素的集合。

关于API方面。Set的API和Collection完全一样。

4. AbstractCollection

AbstractCollection的定义如下:

AbstractCollection是一个抽象类,它实现了Collection中除iterator()和size()之外的函数。

AbstractCollection的主要作用:它实现了Collection接口中的大部分函数。从而方便其它类实现Collection,比如ArrayList、LinkedList等,它们这些类想要实现Collection接口,通过继承AbstractCollection就已经实现了大部分的接口了。

5. AbstractList

AbstractList的定义如下:

public    abstract   class  AbstractList<E>  extends AbstractCollection<E>    implements List<E> {}

AbstractList是一个继承于AbstractCollection,并且实现List接口的抽象类。它实现了List中除size()、get(int location)之外的函数。

AbstractList的主要作用:它实现了List接口中的大部分函数。从而方便其它类继承List。

另外,和AbstractCollection相比,AbstractList抽象类中,实现了iterator()接口。

6. AbstractSet

AbstractSet的定义如下:

public     abstract    class      AbstractSet<E>    extends    AbstractCollection<E>   implements  Set<E> {}

AbstractSet是一个继承于AbstractCollection,并且实现Set接口的抽象类。由于Set接口和Collection接口中的API完全一样,Set也就没有自己单独的API。和AbstractCollection一样,它实现了List中除iterator()和size()之外的函数。

AbstractSet的主要作用:它实现了Set接口中的大部分函数。从而方便其它类实现Set接口。

7. Iterator

Iterator的定义如下:

Iterator是一个接口,它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素。Iterator提供的API接口,包括:是否存在下一个元素、获取下一个元素、删除当前元素。

注意:Iterator遍历Collection时,是fail-fast机制的。即,当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。关于fail-fast的详细内容,我们会在fail-fast总结后面专门进行说明。

8. ListIterator

ListIterator的定义如下:

ListIterator是一个继承于Iterator的接口,它是队列迭代器。专门用于便利List,能提供向前/向后遍历。相比于Iterator,它新增了添加、是否存在上一个元素、获取上一个元素等等API接口。

以上转载:www.jb51.net/article/84821.htm

常见面试题:

1.Collection和Collections的差别?

        java.util.Collection 是一个集合接口,Collection接口在Java类库中有非常多详细的实现。比如List、Set;

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

2、List与Map的差别?

List是存储单列数据的集合,Map是存储key和value这样双列数据的集合,List中存储的数据是有顺序的,而且同意反复。

Map其中存储的数据是没有顺序的,它存储的key是不能反复的,value是能够反复的。

List继承Collection接口,Map不是。Map没有父类

3.List、Map、Set三个接口。存取元素时各有什么特点

首先List和Set都是单列元素的集合。它们有一个共同的父接口Collection。

List内的元素讲究有序性。内部元素可反复。可是Set恰恰相反。它讲究的是无序性,元素不可反复。Set的add方法有一个boolean的返回值,每当add一个新元

素的时候都会调用equals方法进行逐一比較,当新元素与全部的已存在元素的都不反复的时候add成功返回true。否则返回false。

Map与List和Set不同,它是双列存储的(键和值一一相应)。它在存储元素调用的是put方法,每次存储时,要存储一份key和value。不能存储反复的key,这个反复的规则也是利用equals进行比較。取数据的时候则能够依据key获取value。另外还是以获得全部key的集合和全部value的集合。还能够获得key和value组成的Map.Entry对象的集合。

4.ArrayList与LinkedList的区别?

ArrayList和LinkedList两者都实现了List接口,但是它们之间有些不同。

(1)ArrayList是由Array所支持的基于一个索引的数据结构,所以它提供对元素的随机访问,复杂度为O(1),但LinkedList存储一系列的节点数据,每个节点都与前一个和下一个节点相连接。所以,尽管有使用索引获取元素的方法,内部实现是从起始点开始遍历,遍历到索引的节点然后返回元素,时间复杂度为O(n),比ArrayList要慢。

(2)与ArrayList相比,在LinkedList中插入、添加和删除一个元素会更快,因为在一个元素被插入到中间的时候,不会涉及改变数组的大小,或更新索引。

(3)LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点存储了前后节点的引用。

5.ArrayList与Vector的区别?

这两个类都实现了List接口(List接口继承自Collection接口)。它们都是有序集合。它们内部的元素都是能够反复的,都能够依据序号取出当中的某一元素。

它们两个的差别在于:

(1)、线程安全的问题:

        Vector是早期Java就有的,是同意多线程操作的。是线程安全的;而ArrayList是在Java2中才出现,它是线程不安全的,仅仅能使用单线程操作。 因为Vector支持多线程操作,所以在性能上就比不上ArrayList了。(相同的HashTable相比于HashMap也是支持多线程的操作而导致性能不如HashMap。)

(2)、数据增长的问题

        ArrayList和Vector都有一个初始的容量大小,当存储进去它们里面的元素个数超出容量的时候。就须要添加ArrayList和Vector的存储空间,每次添加存储空间的时候不是仅仅添加一个存储单元。是添加多个存储单元。

Vector默认添加原来的一倍,ArrayList默认添加原来的0.5倍。

Vector能够由我们自己来设置增长的大小,ArrayList没有提供相关的方法。

6.HashMap与HashTable的区别?

(1)HashMap允许key和value为null,而HashTable不允许。

(2)HashTable是同步的,而HashMap不是。所以HashMap适合单线程环境,HashTable适合多线程环境。

(3)在Java1.4中引入了LinkedHashMap,HashMap的一个子类,假如你想要遍历顺序,你很容易从HashMap转向LinkedHashMap,但是HashTable不是这样的,它的顺序是不可预知的。

(4)HashMap提供对key的Set进行遍历,因此它是fail-fast的,但HashTable提供对key的Enumeration进行遍历,它不支持fail-fast。

(5)HashTable被认为是个遗留的类,如果你寻求在迭代的时候修改Map,你应该使用CocurrentHashMap。

7.如何决定选用HashMap还是TreeMap?

对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。

8.哪些集合类提供对元素的随机访问?

ArrayList、HashMap、TreeMap和HashTable类提供对元素的随机访问。

9.哪些集合类是线程安全的?

Vector、HashTable、Properties和Stack是同步类,所以它们是线程安全的,可以在多线程环境下使用。Java1.5并发API包括一些集合类,允许迭代时修改,因为它们都工作在集合的克隆上,所以它们在多线程环境中是安全的。

10.并发集合类是什么?

        Java1.5并发包(java.util.concurrent)包含线程安全集合类,允许在迭代时修改集合。迭代器被设计为fail-fast的,会抛出ConcurrentModificationException。一部分类为:CopyOnWriteArrayList、 ConcurrentHashMap、CopyOnWriteArraySet。

11.队列和栈是什么,列出它们的区别?

栈和队列两者都被用来预存储数据。java.util.Queue是一个接口,它的实现类在Java并发包中。队列允许先进先出(FIFO)检索元素,但并非总是这样。Deque接口允许从两端检索元素。

栈与队列很相似,但它允许对元素进行后进先出(LIFO)进行检索。

Stack是一个扩展自Vector的类,而Queue是一个接口。

12.Comparable和Comparator接口是什么?

        如果我们想使用Array或Collection的排序方法时,需要在自定义类里实现Java提供Comparable接口。Comparable接口有compareTo(T OBJ)方法,它被排序方法所使用。我们应该重写这个方法,如果“this”对象比传递的对象参数更小、相等或更大时,它返回一个负整数、0或正整数。但是,在大多数实际情况下,我们想根据不同参数进行排序。比如,作为一个CEO,我想对雇员基于薪资进行排序,一个HR想基于年龄对他们进行排序。这就是我们需要使用Comparator接口的情景,因为Comparable.compareTo(Object o)方法实现只能基于一个字段进行排序,我们不能根据对象排序的需要选择字段。Comparator接口的compare(Object o1, Object o2)方法的实现需要传递两个对象参数,若第一个参数比第二个小,返回负整数;若第一个等于第二个,返回0;若第一个比第二个大,返回正整数。

13..Comparable和Comparator接口有何区别?

Comparable和Comparator接口被用来对对象集合或者数组进行排序。Comparable接口被用来提供对象的自然排序,我们可以使用它来提供基于单个逻辑的排序。

Comparator接口被用来提供不同的排序算法,我们可以选择需要使用的Comparator来对给定的对象集合进行排序。

14.hashCode()和equals()方法有何重要性?

HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。equals()和hashCode()的实现应该遵循以下规则:

(1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。

(2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。

15.通过迭代器fail-fast属性,你明白了什么?

每次我们尝试获取下一个元素的时候,Iterator fail-fast属性检查当前集合结构里的任何改动。如果发现任何改动,它抛出ConcurrentModificationException。Collection中所有Iterator的实现都是按fail-fast来设计的(ConcurrentHashMap和CopyOnWriteArrayList这类并发集合类除外)。

16.fail-fast与fail-safe有什么区别?

Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent中的集合类都为fail-safe的。Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。

集合详细转自:

http://blog.csdn.net/w369033345/article/details/52187411

https://www.cnblogs.com/tlnshuju/archive/2017/04/18/6729467.html

http://www.importnew.com/15980.html

接下来详细介绍下集合中不同集合的区别以及底层原理:

一、ArrayList的实现原理?

1、ArrayList概述?

ArrayList 是 List 接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。

注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。

2. ArrayList 的实现

对于ArrayList而言,它实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作。下面我们来分析ArrayList的源代码:

1) 底层使用数组实现

Java 代码


2)构造方法:

ArrayList 提供了三种方式的构造器,可以构造一个默认初始容量为 10 的空列表、构造一个指定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。

Java 代码

a:构造一个默认初始容量为 10 的空列表的构造器:


ArrayList的默认长度


构造器(初始容量)

b:构造一个指定初始容量的空列表的构造器


构造器

c:构造一个包含指定collection的元素的列表的构造器


构造器

注:详细可见ArrayList的源码。


合并后的三个构造器

3)存储

        ArrayList 提供了 set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection c)、addAll(int index, Collection c)这些添加元素的方法。

下面我们一一讲解:

Java 代码


set(int index, E element)


add(E e)


add(int index, E element)


addAll(Collection c)


addAll(int index, Collection c)

以上均是ArrayList的源码,有兴趣的可以看一下,有助于理解。

4)读取

java 代码


get(int  index)根据索引读取

5)删除

ArrayList 提供了根据下标或者指定对象两种方式的删除功能。如下:

java 代码

第一种:


remove(int   index):根据索引remove

第二种:


remove(Object o):直接remove对象(arraylist中允许有null,所以要分两种情况)

注意:从数组中移除元素的操作,也会导致被移除的元素以后的所有元素的向左移动一个位置。

6)调整数组容量:

        从上面介绍的向ArrayList中存储元素的代码中,我们看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。


源码


整合

从上述代码中可以看出,数组进行扩充时,会将数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其容量的1.5倍。这种操作的代价是很高的,因此在实际使用中,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少是,要在构造ArrayList实例时,就指定其容量,以避免扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。

        ArrayList还给我们提供了将底层数组的容量调整为当前列表保存的实际元素的大小的功能。它可以通过trimToSize方法来实现。代码如下:


trimToSize

7)Fail-Fast机制

        ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着将来某个不确定时间发生任意不确定行为的风险。

二、LinkedList的实现原理?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容

  • title: java集合框架学习总结 tags:集合框架 categories:总结 date: 2017-03...
    行径行阅读 1,667评论 0 2
  • Java 集合框架系列 Java 集合框架_开篇Java 集合框架_ListJava 集合框架_ArrayList...
    wo883721阅读 805评论 0 3
  • 3.3 集合 一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。另...
    闫子扬阅读 707评论 0 1
  • 写下这篇短文的我正值二十岁芳龄,年龄不大,思虑难免不成熟。如有偏激之处,还望见者海涵。 我所见到的关于爱情的模样。...
    Eighter111阅读 226评论 0 1
  • 这三天,我在山东学习,此次来山东主要学习交流青少年思维导图方向的教学模式,思维导图在台湾青少年教学中已是成熟模...
    思维导图培训师陈苏娟阅读 238评论 3 1