Java 集合框架主要包括两种类型的容器:

  一种是集合(Collection),存储一个元素集合,

  另一种是图(Map),存储键/值对映射。

在java中不同的集合底层对应着不同的数据结构

 

一 . Collection接口

  为什么会出现接口:因为集合框架中的很多类 功能是相似的【所以用接口来规范类】

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

  没有使用“泛型”时,Collection中可以存储Object的所有子类型。
  使用了“泛型”之后,Collection中只能存储某个具体的类型。

  集合中不能直接存储基本数据类型,也不能直接存java对象,而是存储java对象的内存地址。

 

Collection中常用方法(接口中的方法属于抽象方法) :

(1)boolean add(Object obj);
向集合中添加Object型元素

(2)int size();
获取集合中元素的个数

(3)void clear();
清空集合中的所有元素

(4)boolean contains(Object o);
判断集合中是否存在某个指定对象

(5)boolean remove(Object o);
删除集合中的指定对象

(6)boolean isEmpty();
判断集合中的元素个数是否为0

(7)Object[] toArray();
把集合中的元素转成数组返回

(8)Iterator iterator();
返回集合中的迭代器对象


Collection包含了List和Set两大分支.注意Map不是Collection的子接口

1.List接口

List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许存储重复元素,可以通过索引来访问指定位置的集合元素。

List接口继承于Collection接口,它可以定义一个允许重复有序集合。因为List中的元素是有序的,所以我们可以通过使用索引来访问List中的元素,这类似于Java的数组。

List接口为Collection直接接口。List所代表的是有序的Collection,实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

集合概述-Collection_时间复杂度

(1)ArrayList

      ArrayList是一个动态数组,它允许任何符合规则的元素插入甚至包括null。每一个ArrayLis实例都有一个初始容量(10), 随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作 (扩展为原来的1.5倍)。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。

集合概述-Collection_数组_02

  数组这种数据结构的特性:

    • 分配内存空间必须是连续的
    • 只能存储一种数据类型,且数组长度固定;
    • 添加,删除的操作慢,由于数组中需要保持内存数据的连续性,所以每次添加和删除元素都会进行大量的数组元素移动

      ArrayList擅长于随机访问 , 根据下标随机访问的时间复杂度是O(1),查找的时间复杂度是O(n) . 同时ArrayList是非同步的。

(2)LinkedList

      LinkedList是一个双向链表。所以它除了有ArrayList的基本操作方法外还额外提供了get,remove,insert等方法,可以在LinkedList的首部或尾部操作元素。

集合概述-Collection_堆栈_03

  链表这种数据结构的特性:

    • 分配内存空间不是必须是连续的;
    • 插入、删除操作很快,只要修改前后指针就OK了,时间复杂度为O(1);
    • 访问比较慢,必须得从第一个元素开始遍历,时间复杂度为O(n);

     LinkedList不能随机访问,因为它所有的操作都是要按照双重链表的顺序执行 , 所以双向循环链表的查询效率低但是增删效率高。在此链表上每一个数据节点都由三部分组成:前指针(指向前面的节点的位置),数据,后指针(指向后面的节点的位置)。最后一个节点的后指针指向第一个节点的前指针,形成一个循环。

      与ArrayList一样,LinkedList也是非同步的。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));

(3)Vector

      与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。

(4)Stack

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


 

2.Set接口

  Set是一种不包含重复的元素的Collection,无序,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。需要注意的是:虽然Set中元素没有顺序,但是元素在set中的位置是由该元素的HashCode决定的,其具体位置其实是固定的。

Set接口有三个具体实现类,分别是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。

(1)HashSet

集合概述-Collection_链表_04

 

 

   HashSet 是一个没有重复元素的集合。它是由HashMap实现的不保证元素的顺序(元素插入的顺序与输出的顺序不一致),而且HashSet允许使用null 元素。HashSet是非同步的.

   HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。

HashSet的实现方式大致如下,通过一个HashMap存储元素,元素是存放在HashMap的Key中,而Value统一使用一个Object对象。

(2)LinkedHashSet

      LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。

(3)TreeSet

     TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。

注意:TreeSet集合不是通过hashcode和equals函数来比较元素的.它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,相同的id判断为重复元素,不会被加入到集合中。