java集合复习

java

java中集合主要有set,list,Map三种,其中List,Set继承自Collection接口,list,set是一个接口,关系如下图所示:

一、List集合

list是一个集合接口,他主要有两个实现类,分别为ArrayList,LinkedList。
List主要特点如下:

1、list中按照索引位置排序。即list是有序的。

2、可以有重复的元素。

3、可以在集合中按照索引位置来检索元素。例如通过list.get(i)的方式来获得集合中的某一个元素。
各实现类特点:

  • ArrayList
    优点: 底层数据结构是数组,查询快,增删慢。
    缺点: 线程不安全,效率高。

  • Vector
    优点: 底层数据结构是数组,查询快,增删慢。
    缺点: 线程安全,但效率低。

  • LinkedList
    优点: 底层数据结构是链表,查询慢,增删快。
    缺点: 线程不安全,但效率高。


二、Set集合

set接口继承自Collection接口,有两个实现类分别为HashSet、TreeSet。LinkedHashSet继承自HashSet接口实现Set接口。

set主要特点如下:

1、元素无序。

2、元素唯一无重复。
各实现类特点:

  • HashSet

    1.底层数据结构是哈希表。

    2.依赖两个方法hashCode()和equals()来保证元素唯一性。

    3.存储无序,唯一。

    4.底层实现是HashMap。

    5.线程不安全。

  • LinkedHashSet

    1.底层数据结构是链表和哈希表。

    2.由链表保证元素有序。

    3.由哈希表保证元素唯一。

    4.元素存放顺序和取出顺序一致。

    5.查询慢,增删快。

  • TreeSet

    1.底层数据结构是红黑树。

    2.元素唯一,且有序,内部会自动排序。

TreeSet的主要功能用于排序
LinkedHashSet的主要功能用于保证FIFO即有序的集合(先进先出)
HashSet只是通用的存储数据的集合
HashSet插入数据最快,其次LinkHashSet,最慢的是TreeSet因为内部实现排序


三、Map集合

Map 是一个键值对 (Key - Value pairs),其中 key 是不可以重复的。

Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。LinkedHashMap继承自HashMap。

  • HashMap:无序且线程不安全,方法是不同步的,效率较高,HashMap允许null值(key和value都允许),HashMap的父类是AbstractMap,时间复杂度为O(1)。

  • LinkedHashMap:这是一个 HashMap + 双向链表 的结构,继承自HashMap,所以既拥有 HashMap 的所有特性还有顺序。

  • TreeMap:是有序的,本质是用二叉搜索树来实现的。

  • HashTable:无序且线程安全,方法是同步的,效率较低,Hashtable不允许null值,Hashtable的父类是Dictionary。

(1)hashmap特点

  • HashMap 的键必须是唯一的,不能重复。
  • HashMap 的键允许为 null,但只能有一个这样的键;值可以有多个 null。
  • HashMap 是无序的,它不保证元素的任何特定顺序。
  • HashMap 不是线程安全的;多线程环境下,建议使用 ConcurrentHashMap,或者使用 Collections.synchronizedMap(hashMap) 将 HashMap 转成线程同步的。
  • 只能使用关联的键来获取值,获取值使用get(key)方法,设置值使用put(key,value)方法。
  • HashMap只能存储对象,所有基本数据类型需使用其包装类型,比如说int应该为Integer。
  • HashMap 实现了 Cloneable 和 Serializable 接口,因此可以拷贝和序列化。

并非所有存放Entry(键值对)的类都是Map接口的子类,比如ThreadLocalMap 。


(2)hashMap实现原理

对于 HashMap 中的每个 key,首先通过 hash function 计算出一个 hash 值,这个hash值就代表了在 buckets 里的编号,而 buckets 实际上是用数组来实现的,所以把这个数值模上数组的长度便得到它在数组的下标,就这样把它放在了数组里。默认的容量是16。如下图所示:

HashMap 底层是 hash 数组和单向链表实现,数组中的每个元素都是链表,由 Node 内部类(实现 Map.Entry接口)实现,HashMap 通过 put & get 方法存储和获取。

存储对象时,将 K/V 键值传给 put() 方法:

HashMap的key为null的Entry(键值对)存放在Array的0位,不会发生hash冲突 。

①调用 hash(K) 方法计算 K 的 hash 值,然后结合数组长度,计算得数组下标;

②调整数组大小(当容器中的元素个数大于 capacity * loadfactor=12 时,容器会进行扩容resize 为 2n);

③有以下几种情况:

i.如果 K 的 hash 值在 HashMap 中不存在,则执行插入,若存在,则发生碰撞;

ii.如果 K 的 hash 值在 HashMap 中存在,且它们两者 equals 返回 true,则更新键值对;

iii. 如果 K 的 hash 值在 HashMap 中存在,且它们两者 equals 返回 false,则插入链表的尾部(尾插法)或者红黑树中(树的添加方式)。

(JDK 1.7 之前使用头插法、JDK 1.8 使用尾插法)(注意:当碰撞导致链表大于 TREEIFY_THRESHOLD = 8 时,就把链表转换成红黑树,链表长度低于6,就把红黑树转回链表)

获取对象时,将 K 传给 get() 方法:

①、调用 hash(K) 方法(计算 K 的 hash 值)从而获取该键值所在链表的数组下标;

②、顺序遍历链表,equals()方法查找相同 Node 链表中 K 值对应的 V 值。

hashCode 是用于定位的,确定元素的存储位置;equals是定性的,比较两者是否相等。


(3)哈希冲突

所谓哈希冲突指的是不同的元素通过hash函数计算出了相同的hash值,而equals不同,因此就造成了哈希冲突。

如果哈希冲突了,会在数组的同一个位置上增加链表用于存储值,如果链表的长度大于 8,将会转化成红黑树进行处理。

HashMap、Hashtable和ConcurrentHashMap都采用链地址法处理hash冲突,而ArrayMap和ThreadLocalMap采用开放地址法。

HashMap 中是通过 hashCode() 和 equals() 方法来保证元素的唯一性。


参考博文:

(1) https://www.jianshu.com/p/63b01b6379fb (List集合详情)

(2) https://blog.csdn.net/zhangqunshuai/article/details/80660974 (list各实现类特性)

以上是 java集合复习 的全部内容, 来源链接: utcz.com/z/390245.html

回到顶部