Map以及HashMap源码笔记

Map

一: 思维导图

 |---- Map: 双列数据, 存储kry-- value对的数据 --- 类似于高中的函数: y = f(x)
             |----HashMap:作为Map主要实现类, 线程不安全效率高
                    |--- LinkedHashMap: 保证在遍历map元素时, 可以按照添加的顺序实现遍历
                        原因: 在原有的HashMap底层结构上,添加了一对指针,指向一前一个和指向后面一个.
                        场景: 对于频繁的遍历操作,此类地执行效率高于HashMap
 
             |---TreeMap:按照添加key-value来进行排序, 实现排序遍历. 此时考虑key的自然排序的定制排序  
                      底层: 使用红黑数
                 |---Hashtable: 作为Map的古老实现类,线程安全,效率低
                        |---Properties: 常用来处理配置文件. key和value都是String类型的.

Map底层 :
数组 + 链表 (jdk7)
数组 + 链表 + 红黑数 (jdk8)

面试题:
①HashMap的底层源码?
② HashMap和Hashtable的异同?
③ CurrentHashMap和Hashtable的异同?

二: Map的结构分析

Map中的key是无序的,不可重复的,使用set存储所有的key --> 自定义的类一定要重写 equals()和 hashCode() (以HashMap为例)
Map中的value 是无序,可以重复的, 使用Collection存储所有的key. --> 自定义的类需要重写equals()
一个键值对: key-value构成了一个Entry的对象 Map中的Entry是无序, 不可重复的; 使用set存储所有的entry

Map中的key相当于函数的 x, value相当于函数的 f(x)

三: HashMap底层源码

*  jdk7
    
*  HashMap map = new HashMap()
*  在实例化之后, 底层创建的一个长度为16的一维数组Entry[] table
    
*  ..........可能已经执行了多次put......
    
*  map.put (key1, value1);
*  首先, 调用key1所在类的hashCode()计算key1的哈希值, 在此哈希值经过某些算法计算之后, 得到Entry数组中的存放位置.
*      如果这个位置上的数据为空, 此时的key1-value1添加成功 ---- 情况一
*      如果这个位置上面的数据不为空, (意味着此位置上存在一个或多个数据(以链表的形式存在)), 比较key1和已存在的一个或多个数据的哈希值:
*              如果key1的哈希值与已存在得哈希值都不相同, 此时key1- value1添加成功 ---情况二
*              如果key1的哈希值已存在的某一个数据(key2-value2)的哈希值相同, 继续比较. 调用key1所在类的equals(key2)
*                      如果equals()的返回为false: 此时key1-value1添加成功 --- 情况三
*                      如果equals()的返回值为true: 使用key1替换key2
*
*     补充: 关于情况二和情况三: 此时key1-value1和原来的数据以链表的方式存储
*
* 在不断的添加过程中会涉及到扩容,但超出临界值时且要存放的位置非空时,扩容. 默认扩容为原来的两倍,
* 并把原有的数据复制过来(实际上重新计算哈希值对应的新数组的位置)
*
* jdk8相较于jdk7在底层实现类的不同:

* 1. new HashMap() 底层没有创建一个长度为16的数组
* 2. jdk8底层的数组是Node()而不是Entry()
* 3. 首次调用put()方法时, 底层才创建长度为16的数组
* 4. jdk7底层结构只有:数组 + 链表 ; jdk8底层则有: 数组 + 链表 + 红黑数
*      当数组的某一个索引位置上的元素以链表的形式存在的数据个数 > 8 且当前数组的长度 >64,
*      此时索引位置上的所有数据改为使用红黑数存储;
*
* DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
* DEFAULT_LOAD_FACTORHashMap的默认加载因子:0.75
* threshold:扩容的临界值,=容量*填充因子:16 * 0.75 => 12
* TREEIFY_THRESHOLDBucket中链表长度大于该默认值,转化为红黑树:8
* MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64

四: LinkedHashMap

 *   底层源码:
 *   static class Entry<K,V> extends HashMap.Node<K,V> {
 *          Entry<K,V> before, after;
 *          Entry(int hash, K key, V value, Node<K,V> next) {
 *          super(hash, key, value, next);
 *     }

五: HashMap中的常用方法:

总结:

  • 增: put(Object key,Object value)
  • 删:remove(Object key)
  • 改:put(Object key,Object value)
  • 查:get(Object key)
  • 插: 没有
  • 长度: size()
  • 遍历: keySet() / values() / entrySet()
@Test
public void test3() {
    HashMap hashMap = new HashMap();
    hashMap.put("AA", 21);
    hashMap.put("CC", 10086);
    hashMap.put(432, 3423);

    Set set = hashMap.keySet();
    Iterator iterator = set.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }

    System.out.println("************************");

    Collection values = hashMap.values();

    for(Object obj : values) {
        System.out.println(obj);
    }

    System.out.println("***************");

    Set entrySet = hashMap.entrySet();
    Iterator iterator2 = entrySet.iterator();
    // 方法一:
    while (iterator2.hasNext()) {
        Object obj = iterator2.next();
        // entrySet中的对象都是Entry类型的, 可以进行强转
        Map.Entry entry = (Map.Entry) obj;
        System.out.println(entry.getKey() + "-->" + entry.getValue());
    }
    // 方法二
    Set keySet = hashMap.keySet();
    Iterator iterator3 = keySet.iterator();
    while (iterator3.hasNext()) {
        Object key = iterator3.next();
        Object Value = hashMap.get(key);
        System.out.println(key + "====" + Value);

    }
}
@Test
public void test2() {
    Map map = new HashMap();
    map.put("AA", 1213);
    map.put("CC", 127);
    map.put("KK", 32112);
    map.put("34", 2344);

    // Object get(Object key):获取指定key对应的value
    Object o = map.get("34");
    System.out.println(o);

    // boolean containsKey(Object key):是否包含指定的key
    System.out.println(map.containsKey("AA"));

    // int size():返回map中key-value对的个对数
    System.out.println(map.size());

    //  boolean isEmpty():判断当前map是否为空
    System.out.println(map.isEmpty());

    // boolean equals(Object obj):判断当前map和参数对象obj是否相等
    HashMap hashMap = new HashMap();
    hashMap.putAll(map);
    System.out.println(hashMap.equals(hashMap));

}

@Test
public void test1() {
    Map map = new HashMap();
    map = new LinkedHashMap();
    // 添加
    map.put("AA", 123);
    map.put("BB", 123);
    map.put("CC", 321);
    map.put("44", 123);
    // 修改
    map.put("AA", 467);
    System.out.println(map);
    // putAll()
    Map map1 = new HashMap();
    map1.put("CC", 321);
    map1.put("DD", 212);
    map1.put("AA", 341221);
    map.putAll(map1);
    System.out.println(map);

    Object value = map.remove("AA"); // 返回value
    System.out.println(map);
    // clear()
    map.clear();
    System.out.println(map.size());

}

六:TreeMap

Person类

public class Person implements Comparable{
    private String name;
    private int id;

    public Person(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }


    @Override
    public int compareTo(Object o) {
        if (o instanceof Person) {
            Person p = (Person) o;
            int i = this.name.compareTo(p.name);
            if (i != 0) {
                return -i;
            }
            return -Integer.compare(p.id, this.id);
        }
        throw new RuntimeException("请输入正确的类型");
    }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", id=" + id + '}';
    }
}
// 自然排序
@Test
public void test1() {
    Map map = new TreeMap();
    Person p1 = new Person("Tom", 212);
    Person p2 = new Person("Jcry", 212);
    Person p3 = new Person("Jack", 212);
    Person p4 = new Person("Jack", 300);

    map.put(p1, 90);
    map.put(p2, 79);
    map.put(p3, 100);
    map.put(p4, 20);

    Set entrySet = map.entrySet();
    Iterator iterator = entrySet.iterator();
    while (iterator.hasNext()) {
        Object obj = iterator.next();
        Map.Entry e = (Map.Entry) obj;
        System.out.println(e.getKey() + "-->" + e.getValue());
    }
}

// 定制排序
@Test
public void test2() {
    Comparator comparator = new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            if (o1 instanceof Person && o2 instanceof Person) {
                Person p1 = (Person) o1;
                Person p2 = (Person) o2;
                return Integer.compare(p1.getId(), p2.getId());
            }
            throw new RuntimeException("请输入正确的类型");
        }
    };


    Map map = new TreeMap(comparator);
    Person p1 = new Person("Tom", 212);
    Person p2 = new Person("Jcry", 212);
    Person p3 = new Person("Jack", 212);
    Person p4 = new Person("Jack", 300);

    map.put(p1, 90);
    map.put(p2, 79);
    map.put(p3, 100);
    map.put(p4, 20);

    Set entrySet = map.entrySet();
    Iterator iterator = entrySet.iterator();
    while (iterator.hasNext()) {
        Object obj = iterator.next();
        Map.Entry e = (Map.Entry) obj; // 强制转化为Map.Entry, 调用getKey()和getValue()
        System.out.println(e.getKey() + "-->" + e.getValue());
    }
}

七: Hashtable

八: Properties

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值