zoukankan      html  css  js  c++  java
  • HashMap

    了解到Java8以后HashMap的实现换了,也看了很多博客一直在向我这个小菜鸡说HashMap的重要。因此我决定洗心革面,好好正视HashMap

    • 基于jdk 8

    先从类注释开始入手学习,顺便提高提高英文水平。如果有任何错误欢迎指出,thanks

     * Hash table based implementation of the <tt>Map</tt> interface.  This
     * implementation provides all of the optional map operations, and permits
     * <tt>null</tt> values and the <tt>null</tt> key.  (The <tt>HashMap</tt>
     * class is roughly equivalent to <tt>Hashtable</tt>, except that it is
     * unsynchronized and permits nulls.)  This class makes no guarantees as to
     * the order of the map; in particular, it does not guarantee that the order
     * will remain constant over time.

    这段注释说,Hashmap基于hash表实现了map接口,并且提供了Map中的所有方法。key,value 允许为null.Hashmap可以粗略的等同与HashTable,但是不同的是HashMap是线程不安全的,并且允许为null.Hashmap并不保证map的顺序.

    知识点

    • HashMap的<key,value>都允许为null
      • 额,这一点,思考了一下还是觉得写段代码验证验证,毕竟代码不会骗我
      • @Test
            public void TestnullValue() {
                Map<String, String> map = new HashMap();
                map.put(null,null);
                map.put("2", "tony");
                System.out.println(map.toString());
            }

        结果

        {null=null, 2=tony}

        好吧,看来编写HashMap的前辈,木有骗我

    • HashMap线程不安全
    • HashMap无序
     * <p>This implementation provides constant-time performance for the basic
     * operations (<tt>get</tt> and <tt>put</tt>), assuming the hash function
     * disperses the elements properly among the buckets.  Iteration over
     * collection views requires time proportional to the "capacity" of the
     * <tt>HashMap</tt> instance (the number of buckets) plus its size (the number
     * of key-value mappings).  Thus, it's very important not to set the initial
     * capacity too high (or the load factor too low) if iteration performance is
     * important.

    emem...说实话读到这一段的时候,我有点难受...要不是我天生聪慧(英文太烂),我可能会被拍死在注释中

    如果hash函数把元素正确的放在容器中,HashMap提供了耗费常量时间的操作, put 和get。迭代整个集合试图耗费的时间与容器的大小有关。因此不要为HashMap设置一个太高的初始值(或者太低的负荷系数)

    负荷系数是扩容的时候需要用到的

    知识点:

    • 理想情况下HashMap的get, put的时间复杂度是O(1)

    什么情况下不是O(1)呢?当发生Hash冲突的时候,时间复杂度就不是O(1)了

     * <p>An instance of <tt>HashMap</tt> has two parameters that affect its
     * performance: <i>initial capacity</i> and <i>load factor</i>.  The
     * <i>capacity</i> is the number of buckets in the hash table, and the initial
     * capacity is simply the capacity at the time the hash table is created.  The
     * <i>load factor</i> is a measure of how full the hash table is allowed to
     * get before its capacity is automatically increased.  When the number of
     * entries in the hash table exceeds the product of the load factor and the
     * current capacity, the hash table is <i>rehashed</i> (that is, internal data
     * structures are rebuilt) so that the hash table has approximately twice the
     * number of buckets.

    影响HashMap性能的因素有两个,容量和负荷因子。

    初始容量是创建hash表的时候就确定的,负荷因子用来判断是否允许自动扩容。当hash表中的数量超过容器的大小*负荷因子的时候.Hash表要再做一次内部构建,扩容为原来的两倍.

     * <p>As a general rule, the default load factor (.75) offers a good
     * tradeoff between time and space costs.  Higher values decrease the
     * space overhead but increase the lookup cost (reflected in most of
     * the operations of the <tt>HashMap</tt> class, including
     * <tt>get</tt> and <tt>put</tt>).  The expected number of entries in
     * the map and its load factor should be taken into account when
     * setting its initial capacity, so as to minimize the number of
     * rehash operations.  If the initial capacity is greater than the
     * maximum number of entries divided by the load factor, no rehash
     * operations will ever occur.

    一般负荷因子的数值是0.75 它平衡了时间和空间复杂度。 负载因子值越大空间开销越大,但是查找的开销就越低。HashMap的绝大部分操作都是Get Put,

    当哈希表中entry的总数少于负载因子和初始容量乘积时, 就不会发生rehash(内部重新构建)动作

     * <p>If many mappings are to be stored in a <tt>HashMap</tt>
     * instance, creating it with a sufficiently large capacity will allow
     * the mappings to be stored more efficiently than letting it perform
     * automatic rehashing as needed to grow the table.  Note that using
     * many keys with the same {@code hashCode()} is a sure way to slow
     * down performance of any hash table. To ameliorate impact, when keys
     * are {@link Comparable}, this class may use comparison order among
     * keys to help break ties.
     *

    如果有大量的数值需要被存储到HashMap中,那么要确保初始够大,防止map rehash自动扩容增大开销。

    使用大量keys转换后的hash地址相同会降低hash表的效率,因此当keys支持java.lang.Comparable的时候,可以利用排序降低影响。

     * <p><strong>Note that this implementation is not synchronized.</strong>
     * If multiple threads access a hash map concurrently, and at least one of
     * the threads modifies the map structurally, it <i>must</i> be
     * synchronized externally.  (A structural modification is any operation
     * that adds or deletes one or more mappings; merely changing the value
     * associated with a key that an instance already contains is not a
     * structural modification.)  This is typically accomplished by
     * synchronizing on some object that naturally encapsulates the map.

    HashMap是线程不安全的,如果多个线程同时访问hash map,至少有一个线程修改了表结构,那么必须加锁。

    (改变表结构指的是,添加或删除一个或多个映射,如果是改变values值不是修改表结构)

    当多个线程操作hashmap的时候,一般使用同步对象锁锁住map上

     * If no such object exists, the map should be "wrapped" using the
     * {@link Collections#synchronizedMap Collections.synchronizedMap}
     * method.  This is best done at creation time, to prevent accidental
     * unsynchronized access to the map:<pre>
     *   Map m = Collections.synchronizedMap(new HashMap(...));</pre>

    如果不存在这样的对象时,应该调用Collections.synchronizedMap把HashMap转化成线程安全的SynchronizedMap

      public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
            return new SynchronizedMap<>(m);
        }

     *
     * <p>The iterators returned by all of this class's "collection view methods"
     * are <i>fail-fast</i>: if the map is structurally modified at any time after
     * the iterator is created, in any way except through the iterator's own
     * <tt>remove</tt> method, the iterator will throw a
     * {@link ConcurrentModificationException}.  Thus, in the face of concurrent
     * modification, the iterator fails quickly and cleanly, rather than risking
     * arbitrary, non-deterministic behavior at an undetermined time in the
     * future.

    iterators会返回所的集合视图方法。如果iterator迭代器被创建了以后,map修改了表结构(除了iterator自身的remove),iterator会抛出ConcurrentModificationException异常。因此在并发修改的时候修改表结构操作会失败

    @Test
        public void test() {
            Map<String, String> map = new HashMap();
            map.put("1", "tony");
            map.put("2", "tony");
            Set<Map.Entry<String, String>> entries =  map.entrySet();
            Iterator<Map.Entry<String, String>> iterator = entries.iterator();
            while (iterator.hasNext()) {
                if (iterator.next().getKey().equals("1")) {
                    //不报错
                    iterator.remove();
                    //报错
                    map.put("3", "tony");
                }
            }
            System.out.println(map.toString());
        }
  • 相关阅读:
    Oracle DB 管理数据库的空间
    五 Django 1.5.4 User Authentication 用户认证
    接口开放在即,先学招行做好微信内容营销
    WPF的ItemsControl设置数据源以及Binding使用
    WPF中后台代码停止RepeatBehavior=RepeatBehavior.Forever的办法
    WPF中使用RenderTransformOrigin来控制动画的起点
    使用Rectangle+ImageBrush来代替Image,解决图片模糊的问题
    WPF中Style文件引用另一个Style文件中的样式
    WPF中用后台C#代码为TabItem设置Background属性
    WPF中设置Border的BorderThickness属性会让背景图片产生模糊感
  • 原文地址:https://www.cnblogs.com/amberbar/p/10044314.html
Copyright © 2011-2022 走看看