Java集合之Map(三)

一. 概述

Map集合,即Mapping的缩写,采用数学里面的一 一映射原理,计算机术语叫做键值对,即每一个key对应一个value,因此他是集合里面每次存储两个数据的(key和对应的value),即称作为双列集合
下面会详细介绍两个Map(HashMap ,HashTable)的区别

二. HashMap &&HashTable之间的区别

1.最重要的:线程安全(切记,面试点)

Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步。
HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。具体的原因在后续的博客中进行多线程安全的分析。使用HashMap时就必须要自己增加同步处理,
虽然HashMap不是线程安全的,但是它的效率会比Hashtable要好很多。

2.父类不同

背景
Hashtable是java一开始发布时就提供的键值映射的数据结构,而HashMap产生于JDK1.2。虽然Hashtable比HashMap出现的早一些,但是现在Hashtable基本上已经被弃用了。而HashMap已经成为应用最为广泛的一种数据类型了。造成这样的原因一方面是因为Hashtable是线程安全的,效率比较低。另一方面可能是因为Hashtable没有遵循驼峰命名法吧…也有地方称Hashtable是1.0版双列集合

HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口


3.方法个别不同

Hashtable比HashMap多提供了elments() 和contains() 两个方法。
elments() 方法继承自Hashtable的父类Dictionnary。

elements() 方法用于返回此Hashtable中的value的枚举。

contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。
事实上,contansValue() 就只是调用了一下contains() 方法,而contansValue()两者都有这个方法,个人感觉多一个contains()方法多余了。


4. 对Null key 和Null value的支持不同

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明。

    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

在这里插入图片描述

HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。

		Map<String ,String> hashmap = new HashMap<>();
        hashmap.put(null,"一");
        hashmap.put(null,"二");
        Set<Entry<String ,String>> entrySet = hashmap.entrySet();
        Iterator<Entry<String ,String>> iterator2 = entrySet.iterator();
        while (iterator2.hasNext()){
            Entry<String, String> entry2 = iterator2.next();
            System.out.println(entry2);
            System.out.println(entry2.getKey() + " " + entry2.getValue());

5.初始容量大小和每次扩充容量大小的不同

Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。
HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。

6.分析为什么Hashtable没有HashMap查询速度

1.当然最重要的是多线程的区别(前面说过了,这里就不重复了)

2.两者计算hash不同:

为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置。
Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。
HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算
为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。当然了,为了高效,HashMap只做了一些简单的位处理。从而不至于把使用2 的幂次方带来的效率提升给抵消掉

3.存放数据方式不同

补充:哈希表的介绍

在这里插入图片描述

哈希表(散列表):是由数组+链表的组成的
HashMap每个哈希桶(也就是每个数组存放链表结构的位置)里面存放的链表长度超过8的时候,就会自己改变结构,变成红黑树结构,这样查询效率便会更加高效,然后当去除数据,即链表长度小于6的时候(注意此时还是红黑树结构),红黑树就会自动还原成链表结构

1道比较坑的面试题:当HashMap某个哈希桶中链表长度7时,再在这个哈希桶中添加1个数据,此时这个哈希桶中数据结构会有什么变化?
答:如果此时是红黑树,则数据结构不变;如果此时是链表结构,则会变成红黑树结构。

众所周知:二叉树(红黑树)查询数据效率比链表查询效率高效得多,所以当一个哈希桶中数据较多时,HashMap效率明显优于HashTable

3.TreeMap(Java集合之Set(二)-TreeSet补充)

(1).底层原理

在博文:Java集合之Set(二)中有提到,TreeSet的实现其实引用了TreeMap,唯一的区别在于,TreeMap是双列集合,键不能为null,而TreeSet则是单列集合,只需要存储TreeMap的key就可以了,就能实现它的单列集合,有序,不重复的效果了。
TreeMap
TreeMap实现了SotredMap接口,它是有序的集合。而且是一个红黑树结构,每个key-value都作为一个红黑树的节点。如果在调用TreeMap的构造函数时没有指定比较器,则根据key执行自然排序。

(2).排序

而一般用到TreeMap,就是它的排序特点了
TreeMap提供了四个构造方法,实现了方法的重载。无参构造方法中比较器的值为null,采用自然排序的方法,如果指定了比较器则称之为定制排序.

自然排序:TreeMap的所有key必须实现Comparable接口,所有的key都是同一个类的对象
定制排序:创建TreeMap对象传入了一个Comparator对象,该对象负责对TreeMap中所有的key进行排序,采用定制排序不要求Map的key实现Comparable接口。
详情参照:专门讲述TreeMap的底层原理实现

3.Map集合的输出

输出方式有两种:都是通过Map集合转换成Set集合

package com.kaikeba.practice0925;

import java.util.*;
import java.util.Map.*;

public class PracticeMap {
    public static void main(String[] args) {
        Hashtable<String ,String> hashtable = new Hashtable<>();
        hashtable.put("1","一");
        hashtable.put("2","二");
        Set<String> keySet = hashtable.keySet();
        Iterator<String> iterator = keySet.iterator();
        System.out.println("输出方式1:");
        while (iterator.hasNext()){
            String i = iterator.next();
            System.out.println(i + "" + hashtable.get(i));
        }
        System.out.println();
        System.out.println("输出方式2:");
        Map<String ,String> hashmap = new HashMap<>();
        hashmap.put("1","一");
        hashmap.put(null,"二");
        Set<Entry<String ,String>> entrySet = hashmap.entrySet();
        Iterator<Entry<String ,String>> iterator2 = entrySet.iterator();
        while (iterator2.hasNext()){
            Entry<String, String> entry2 = iterator2.next();
            System.out.println(entry2);
            System.out.println(entry2.getKey() + " " + entry2.getValue());
        }

    }
}

输出:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值