2021/8/19

HashMap

  • 用于私聊服务器存副线程,并将该线程转发给聊天对象
  1. hashmap 他是一个允许空的entry(key-value)键值对,,以键值对存储数据。

  2. 是一个非线程安全的容器,如果多个线程同时影响了 HashMap ,并且至少一个线程修改了 HashMap 的结构,那么必须对 HashMap 进行同步操作

    可以使用 Collections.synchronizedMap(new HashMap) 来创建一个线程安全的 Map。*想构造安全的map可以使用 ConcurrentHashMap

  3. hashmap是无序的,无法保证内部存储的键值对的有序性。

  4. hashmap底层数据结构是数组+链表的集合体,数组在 HashMap 中又被称为桶(bucket)。遍历 HashMap 需要的时间损耗为 HashMap 实例桶的数量 + (key - value 映射) 的数量

  5. hashmap 有两个重要因素,初始容量和负载因子初始容量指的就是 hash 表桶的数量负载因子是一种衡量哈希表填充程度的标准,当哈希表中存在足够数量的 entry,以至于超过了负载因子和当前容量,这个哈希表会进行 rehash 操作,内部的数据结构重新 rebuilt。

  6. HashMap 会导致除了迭代器本身的 remove 外,外部 remove 方法都可能会导致 fail-fast 机制,因此尽量要用迭代器自己的 remove 方法。如果在迭代器创建的过程中修改了 map 的结构,就会抛出 ConcurrentModificationException 异常。

  7. 迭代器

  8. iterator

hashmap与hashTable

相同

HashMap 和 HashTable 都是基于哈希表实现的,其内部每个元素都是 key-value 键值对都实现了 Map、Cloneable、Serializable 接口。

不同

  • 父类不同

    • hashmap继承了AbstractMap类
    • HashTable 继承了 Dictionary
  • 空值不同

    • HashMap 允许空的 key 和 value 值,把 Null key 当做普通的 key 对待
    • HashTable 不允许空的 key 和 value 值,不允许 null key 重复,如果重复则会抛出空指针异常
  • 线程安全

    • HashMap 不是线程安全的,如果多个外部操作同时修改 HashMap 的数据结构比如 add 或者是 delete,必须进行同步操作,仅仅对 key 或者 value 的修改不是改变数据结构的操作。可以选择构造线程安全的 Map 比如 Collections.synchronizedMap 或者是 ConcurrentHashMap。
    • HashTable 本身就是线程安全的容器。
  • 性能不同

    • HashMap 进行 put 或者 get 操作,可以达到常数时间的性能
    • HashTable 的 put 和 get 操作都是加了 synchronized 锁的,所以效率很差。
  • 初始容量不同

    • HashMap 的初始长度为16,之后每次扩充变为原来的两倍。创建时,如果给定了容量初始值,那么HashTable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。
    • HashTable 的初始长度是11,之后每次扩充容量变为之前的 2n+1(n为上一次的长度)

hashmap与hashSet

HashSet 继承于 AbstractSet 接口,实现了 Set、Cloneable,、java.io.Serializable 接口。

HashSet 不允许集合中出现重复的值。

HashSet 底层其实就是 HashMap,所以对 HashSet 的操作其实就是对 HashMap 的操作。

所以 HashSet 也不保证集合的顺序。

hashMap底层结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ncU7x9vH-1629378660323)(D:\笔记\JAVA学习笔记\14笔记\image-20210819145626779.png)]

AbstractMap类

  1. 该类是Map接口的主要实现。
  2. 不修改map,必须继承该类并且提供entrySet方法即可。返回的集合将在AbstractSet 之上实现。这个set不应该支持 add 或者 remove 方法,并且它的迭代器也不支持 remove 方法。
  3. 为了实现可修改的 map必须**重写这个类的 put 方法(否则就会抛出UnsupportedOperationException),**并且 entrySet.iterator() 返回的 iterator 必须实现 remove() 方法。、

Map接口

  1. 定义了 key-value 键值对的标准,一个对象支持 key-value 存储。Map不能包含重复的 key,每个键最多映射一个值

  2. 代替了Dictionary 类,Dictionary是一个抽象类而不是接口

  3. 提供了三个集合的构造器,map的顺序定义为map映射集合上的迭代器返回其元素的顺序

  4. map实现:

    TreeMap类,保证了map的有序性

    HashMap,则没有保证。

    LinkedHashMap继承HashMap,元素既可以按照它们插入图的顺序排序,也可以按它们最后一次被访问的顺序排序

内部类和接口

Node接口

  1. 存储HashMap的实例,实现了Map.Entry接口

  2. 存储四个属性,

    • hash值:final int hash
    • 键 :final K key
    • 值:V value
    • 指向下一个Node节点的Node类型:Node next
  3. Map.Entry 是一条条entry 链连接在一起的,所以Node节点也是一条条entry链。

    构造一个新的HashMap实例的时候,会把这四个属性值分为传入

    Node(int hash, K key, V value, Node next) {this.hash =hash;                              this.key = key;
     this.value = value;                            this.next = next;
    }
    

KeySet类

  1. keySet 类继承于 AbstractSet 抽象类,它是由 HashMap 中的 keyset() 方法来创建 KeySet 实例的,旨在对HashMap 中的key键进行操作
  2. map.keySet() 其实是返回了一个 Set 接口,KeySet() 是在 Map 接口中进行定义的,不过是被HashMap 进行了实现操作
返回一个set视图,这个视图中包含了map中的key。
public Set<K> keySet() {// keySet 指向的是 AbstractMap 中的 keyset
        Set<K> ks = keySet;
        if (ks == null) {// 如果 ks 为空,就创建一个 KeySet 对象// 并对 ks 赋值
            ks = new KeySet();
            keySet = ks;
        }
        return ks;
    }

4.所以KeySet都是对Map中的Key进行操作

Values类

  1. Values 旨在对key-value 键值对中的 value 值进行使用,看一下代码示例:
public Collection values() {// values 其实是 AbstractMap 中的 values
  Collection vs = values;if (vs == null) {
    vs = new Values();
    values = vs;
  }return vs;
}
  1. 所有的 values 其实都存储在 AbstractMap 中,而 Values 类其实也是实现了 Map 中的 Values 接口,源码操作方法:
  final class Values extends AbstractCollection<V> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator<V> iterator()     { return new ValueIterator(); }
        public final boolean contains(Object o) { return containsValue(o); }
        public final Spliterator<V> spliterator() {
            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
        }
        public final void forEach(Consumer<? super V> action) {
            Node<K,V>[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                int mc = modCount;
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
                        action.accept(e.value);
                }
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }
    }

EntrySet内部类

  1. key-value 键值对进行操作的内部类
// 返回一个 set 视图,此视图包含了 map 中的key-value 键值对
public Set<> entrySet() {
  Set> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值