java 集合Collection 子接口:List接口  set接口   queue 接口

目录

概述

collection接口

Map

细说:

 Hashtable和HashMap的区别: 

ConcurrentHashMap 


概述

所有集合的顶级接口Collection

子接口:List接口  set接口   queue 接口

List接口:实现类有ArrayList  linkedList   stack  vector

set接口: 

  1. HashSet 底层是使用HashMap(底层是数组加链表)
  2. LinkedHashSet:保证数据有序
  3. TreeSet:能排序

Queue接口:先进先出

list和set是实现了collection接口的。Map不是collection的子接口或者实现类。Map是一个接口
 

jdk1.8图

collection接口:

Map:

List:

  1. 可以允许重复的对象。
  2. 可以插入多个null元素。
  3. 是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
  4. List中提供索引的方式来添加元素和获取元素,由此可见List集合可是达到精确的存储和获取,
  5. 常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

Set:

  1. 不允许重复对象
  2. 只允许一个 null 元素
  3. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator  或者 Comparable 维护了一个排序顺序。
  4. 传入的参数都是对象,而Set只能一个一个的比较,显然效率和实用性是比不上List集合的
  5. Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSetTreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。

Map

  1. Map不是collection的子接口或者实现类。Map是一个接口。
  2. Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
  3. TreeMap 也通过 Comparator  或者 Comparable 维护了一个排序顺序。
  4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键
  5. Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap.(HashMap、TreeMap最常用)

2.面试题:什么场景下使用list,set,map呢?优缺点

  1. 如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。

  2. 如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。

  3. 如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。

  4. 如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。

细说:

List 的实现类有 ArrayList,Vector 和 LinkedList:

  1. ArrayList: 底层使用数组来实现,可以自动扩容,初始容量默认是10,每一增加原有长度的一半增删比较慢 查询速度快,线程不安全的一个列表
  2. LinkedList:增删快   查询慢  线程不安全,内存不连续
  3. Vector是JDK1.0出现。底层使用数组实现,向量 :默认容量是10,默认每次扩容是原来容量的一倍如果是写了增量,那么是原来容量加增量。直接子类是Stact增删慢 查询快,Vector的方法都是同步方法,线程安全的集合。  .Enumeration 是JDK1.0出现。现在不常用。被iterator替代。Collention接口的父接口是Iterable,增强for循环本质上就是迭代器.

  4. stack栈是vector的子类,先进后出。入栈/压栈:存数据,将数据从栈顶压到栈底。出栈/弹栈:取数据,将数据从栈底传到栈顶。

  5. Queue(队列):先进先出, 接口,父接口Collection

  6. 数组可以储存对象,也可以存储基本数据类型 Person[]
    集合中不可以存放基本数据类型:Collection<E> :泛型,泛型的类型必须是引用数据类型
  7. 如果数据决定了查询和增删效率差不多,那么优先选择ArrayList还是LinkedList??

    选择LinkedList。因为LinkedList是内存不连续的。ArrayList是内存连续的。

Set 散列集合的实现类有 HashSet 和 TreeSet;

  1. HashSet:底层是由哈希表线程不安全,默认的初始容量是16,HashSet指定初始容量,底层会保证结果一定是2的n次方的形式:10-->16    17 -->32
  2. LinkedHashSet:是有序的集合(每一个桶之间的链表也有联系),不会扩容
  3. TreeSet:TreeSet 使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序。

Map 接口有三个实现类:Hashtable,HashMap,TreeMap,LinkedHashMap;

  1. HashMap实现不同步,线程不安全。  HashTable线程安全 , HashMap中的key-value都是存储在Entry中的。 HashMap可以存null键和null值,不保证元素的顺序恒久不变,通过hashCode()方法和equals方法保证键的唯一性 
  2. Hashtable:内部存储的键值对是无序的是按照哈希算法进行排序,与 HashMap 最大的区别就是线程安全。键或者值不能为 null,为 null 就会抛出空指针异常。
  3. LinkedHashMap有序的 Map 集合实现类,相当于一个,先 put 进去的最后出来,先进后出。
  4. TreeMap:基于红黑树 (red-black tree) 数据结构实现,按 key 排序,默认的排序方式是升序。

补充:HashMap实际上是一个 HashMap 实例,HashMap底层是数组加链表,数组的每一个位置称之为桶,每一个桶上都是链表,存数据的时候,先计算是0-15哪个值,寻找对应的桶,在存放进桶的时候,要先和桶里面的数据进行对比,如果相等就舍弃,存放在链表的最前面,扩容后,会将原来的所有数据重新计算,重新存放的过程叫rehash,扩容的加载因子的0.75(太小频繁扩容,太大链表内容会过多,影响效率),初始容量是16(太小:链表内容会过多,影响效率太大:浪费内存),每次扩容都会增加原来的一倍的数量,注意:,一个桶中存放10000个数据,其他桶中没有数据,那么会不会扩容,不会JDK1.8之后(链表长度超过8之后)会将桶中的链式栈结构扭转为二叉树结构,从而提升效率,)支持的;是无序的,不保证 set 元素的迭代顺序,不保证数据的位置(数据位置是可能发生改变的)

 解决冲突主要有三种方法:定址法,拉链法,再散列法。HashMap是采用拉链法解决哈希冲突的。

  1. 链表法是将相同hash值的对象组成一个链表放在hash值对应的槽位;    
  2. 用开放定址法解决冲突的做法是:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。 沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。  
  3. 拉链法解决冲突的做法是: 将所有关键字为同义词的结点链接在同一个单链表中 。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。拉链法适合未规定元素的大小。    

 2.  Hashtable和HashMap的区别: 


 a)   继承不同。  public class Hashtable extends Dictionary implements Map public class HashMap extends  AbstractMap implements Map 
 b)  HashMap线程不安全。  HashTable线程安全 。Hashtable中的方法是同步的,而HashMap中的方法是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。 
 c)  Hashtable 中, key 和 value 都不允许出现 null 值。 在 HashMap 中, null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null 。当 get() 方法返回 null 值时,即可以表示 HashMap 中没有该键,也可以表示该键所对应的值为 null 。因此,在 HashMap 中不能由 get() 方法来判断 HashMap 中是否存在某个键, 而应该用 containsKey() 方法来判断。 
 d)  两个遍历方式的内部实现上不同。Hashtable、HashMap都使用了Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。 
 e)  哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。 
 f)  Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式

  1. HashTable中hash数组默认大小是11,增加的方式是old*2+1
  2. HashMap中hash数组的默认大小是16,而且一定是2的指数。  
  3.  注:  HashSet子类依靠hashCode()和equal()方法来区分重复元素。      
  4. HashSet内部使用Map保存数据,即将HashSet的数据作为Map的key值保存,这也是HashSet中元素不能重复的原因。而Map中保存key值的,会去判断当前Map中是否含有该Key对象,内部是先通过key的hashCode,确定有相同的hashCode之后,再通过equals方法判断是否相同。

ConcurrentHashMap 

  1. ConcurrentMap 并发映射:继承了Map接口,支持并发操作,并且保证并发操作过程中的安全性
  2. ConcurrentHashMap 并发哈希映射:实现了Map接口,底层是基于数组+链表结构来存储,默认初始容量是16,默认加载因子是0.75,每次扩容默认增加一倍
  3. 异步式线程安全:采取的分桶/段锁机制 - 当有线程操作某个键值对的时候,会将这个键值对所在的桶整体锁起来,此时不影响其他桶的操作
  4. 在后续版本中,为了提高效率,在分桶锁的基础上,引入了读写锁:读锁:允许多个线程同时读,但是不允许线程写。写锁:只允许一个线程写, 但是不允许线程读
  5. 在CPU中,一旦引入了线程锁的问题,就会导致CPU的资源耗费比较严重,也因此在JDK1.8中,引入了锁算法CAS(和内核相关的,必须计算机内核支持才能使用CAS) - Compare And  Swap - 我认为V的值应该是A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少 - 避免锁机制带来的CPU开销。先并发进程,在抢占进程,提高并发。
  6. 从JDK1.8开始,在桶的基础上引入了红黑树机制。当桶中的元素超过8个的时候,会将桶中的链表扭转成一棵红黑树;如果桶中的元素不足7个,则将红黑树再扭转回链表,树化的最小容量是64桶数量,>=64,才会启动红黑树,
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值