面试中遇到的Map接口问题

        前段时间一个实习的面试遇到了map接口的问题,面试官让我说出几种Map的实现类以及它们的区别,在说到谁是线程安全的问题上出现了知识欠缺,所以在这里重新整理一下java中的集合并详细介绍一下Map接口的相关知识。

         根据学习,Java 集合可分为 Collection Map 两种体系 。

Collection接口:单列数据,定义了存取一组对象的方法的集合,它是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。

注意:JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List) 实现。

                                               Set:元素无序、不可重复的集合          

                                               List:元素有序、可重复的集合

       

Map接口:双列数据,保存具有映射关系“key-value对”的集合

注意:

1.Map 中的 key 和 value 都可以是任何引用类型的数据

2.Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应 的类,须重写hashCode()和equals()方法

3.常用String类作为Map的“键”

4.key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到 唯一的、确定的 value

5.Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用频率最高的实现类

Map接口主要有以下几个实现类:

 Hashmap 

1.它是 Map 接口使用频率最高的实现类。

2.它允许使用null键和null值,与HashSet一样,不保证映射的顺序。

3.所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写: equals()和hashCode()

4.所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类 要重写:equals()

5.一个key-value构成一个entry

6.所有的entry构成的集合是Set:无序的、不可重复的

7.HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true, hashCode 值也相等。

8.HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。

注意:JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)

JDK 8版本发布以后:HashMap是数组+链表+红黑树实现。当链表数量大于8时,结构转化为红黑树。

问:负载因子值的大小,对HashMap有什么影响 ?

1. 负载因子的大小决定了HashMap的数据密度。

2.负载因子越大密度越大,发生碰撞的几率越高,数组中的链表越容易长, 造成查询或插入时的比较次数增多,性能会下降。

3.负载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的 几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性 能会更高。但是会浪费一定的内容空间。而且经常扩容也会影响性能,建议初始化预设大一点的空间。

4.按照其他语言的参考及研究经验,会考虑将负载因子设置为0.7~0.75,此时平均检索长度接近于常数

问:hashCode() 和equals() 方法的重要性体现在什么地方?

Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的hash值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对HashMap的精确性和正确性是至关重要的。

ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEntry 用来封装映射表的键 / 值对;Segment 用来充当锁的角色,每个 Segment 对象守护整个散列映射表的若干个桶。每个桶是由若干个 HashEntry 对象链接起来的链表。一个 ConcurrentHashMap 实例中包含由若干个 Segment 对象组成的数组。HashEntry 用来封装散列映射表中的键值对。在 HashEntry 类中,key,hash 和 next 域都被声明为 final 型,value 域被声明为 volatile 型。

static final class HashEntry<K, V> {

       
    final K key;                       // 声明 key 为 final 型

                   
    final int hash;                   // 声明 hash 值为 final 型

                   
    volatile V value;                 // 声明 value 为 volatile 型

                   
    final HashEntry<K, V> next;      // 声明 next 为 final 型

              

                   

    HashEntry(K key, int hash, HashEntry<K, V> next, V value) {

           this.key = key;

           this.hash = hash;

           this.next = next;

           this.value = value;

       }

}

在ConcurrentHashMap 中,在散列时如果产生“碰撞”,将采用“分离链接法”来处理“碰撞”:把“碰撞”的 HashEntry 对象链接成一个链表。由于 HashEntry 的 next 域为 final 型,所以新节点只能在链表的表头处插入。

注意:由于只能在表头插入,所以链表中节点的顺序和插入的顺序相反。

Segment 类继承于 ReentrantLock 类,从而使得 Segment 对象能充当锁的角色。每个 Segment 对象用来守护其(成员对象 table 中)包含的若干个桶。

 注意:Concurrenthashmap是线程安全的!(就这里说错了= =)

Hashtable

1.Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。

2.Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用。

3.与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value

4.与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序

5.Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。

LinkedHashMap 

1.LinkedHashMap 是 HashMap 的子类

2.在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序

3.与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代 顺序:迭代顺序与 Key-Value 对的插入顺序一致

TreeMap

1.TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。 TreeMap 可以保证所有的 Key-Value 对处于有序状态。

2.TreeSet底层使用红黑树结构存储数据

3.TreeMap 的 Key 的排序:

        3.1 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException

        3.2 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口

4.TreeMap判断两个key相等的标准:两个key通过compareTo()方法或 者compare()方法返回0。

Properties

1.Properties 类是 Hashtable 的子类,该对象用于处理属性文件

2.由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型

3.存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值