zoukankan      html  css  js  c++  java
  • Map集合-主要HashMap和Hashtable

    JAVA8除了给Map集合新增了方法remove(Object key,Object value)默认方法外

    还增加了以下方法

    Object replace(Object key,Object value),与put方法不同,他如果发现原来key不存在也不会增加新的key-value

    boolean  replace(Object key,V Oldvalue,V Newvalue)

    Object putIfAbsent(Object key,Object value)自动检测该key对应的VALUE是否为空,如果为空,则用value替换原来的 NULL

    Object getOrDefault(Object key,V defaultValue)获得指定的Key的value,如果为空就返回默认值defaultValue

    其他方法似乎不常用,用到再补充啦

    HashMap与HashTable的关系好像ArrayList与Vetor,HashTable比较老旧,HashMap是改进版本,在存在key冲突时候依然有比较好的性能(HashMap采用链表解决冲突)

    他们有以下两个典型的区别、

    HashMap是线程不安全的,HashTable是线程安全的,所以HashMap有比较好的性能。但是如果多个线程访问Map集合,HashTable的性能更好(尽量少用HashMap

    HashTable键值对都不能放null作为key,value HashMap可以null为空,不能重复,value可以多个空

    看如下代码:

    package Test01;
    
    import java.util.HashMap;
    
    public class TestHashMap {
      public static void main(String[] args) {
        HashMap m  = new HashMap();
        m.put(null, null);
        m.put(null, null);
        m.put("a", "9");
        System.out.println(m);
    }
    }

     运行结果可看,不能把两个null放入HashMap

    为了成功在HashMap和HashTable中存储对象,作为Key的Object 的对象必须实现hashcode()和equals方法。也就是说作为key的对象,通过equals返回true后,hashcode()值也必须相等。

    那么对于value值呢,HashMap和HashTable都有containValue方法,可判断是否包含了指定的value,那如何判断value相等呢?返回equals比较相等即可。

    package Test01;
    
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.SortedSet;
    import java.util.TreeSet;
     class C{
        public int count;
        public  C(int count) {
            this.count =count;
        }
        public  boolean equals(Object obj) {
            if(this == obj) {
                return true;
            }
            if(obj != null && obj.getClass() == C.class) {
                C m =(C) obj;
                return this.count == m.count;
            }
            return false;
        }
        public  int hashcode() {
            return this.count;
        }
        public String toString() {
            return "试试C[count=" + count + "]";
        }
         
    }
    class B{
    
        @Override
        public boolean equals(Object arg0) {
            // TODO Cuto-generated method stub
            return true;
        }
        
    }
    public class TestMap{
       @SuppressWarnings("unchecked")
    public static void main(String[] args){
           HashMap m =new HashMap();
           B b= new B();
           m.put(new C(200), "第一次");
           m.put(new C(39), "第二次");
           m.put(new C(450), "第三次");
           m.put(new C(2222), b);
           System.out.println(b.equals("erer "));
          System.out.println( m.containsValue("测试字符串"));   //按理不是返回true,结果返回false
        }
    }

     与HashSet类似,也尽量不要把可变对象作为hashMap和Hashtable作为key,如果非得,也尽量不要在程序里修改他的实例变量。

    HashSet有个子类是LinkedHashSet,hashMap也有子类LinkedhashMap子类    LinkedhashMap用一个双向链表维护Key-value顺序。迭代顺序和插入顺序一致。可以维持顺序的同时又避免使用TreeMap增加的成本。

    package Test01;
    
    import java.util.LinkedHashMap;
    
    public class D{
      public static void main(String[] args) {
        LinkedHashMap  m =new LinkedHashMap();
        m.put("语文", 80);
        m.put("数学", 23);
        m.put("英语", 123);
        m.forEach((key,value) -> System.out.println( key +" -->"+value));
    }
    }

     下面讲解下Properties类,他是Hashtable的子类(Properties类是一个Key,value都是String类的Map),它处理属性文件(windows的Ini文件就是一种属性文件)特别方便。有以下方法

    String getProperty(String key)获得指定属性名的属性值

    String getProperty(String key,String defaultValue)获得指定属性名的属性值,如果没有,就设置为defaultValue

    Object  setProperty(String key,String Value)设置属性值,;类似Hashtable的put方法

    另外还有两种方法读写属性文件

     void load(InputStream inputStream) 从属性文件中(以输入流的形式展示)加载属性值,把加载到的Key-value追加到Properties类里。

    void store(OutputStream outputStream,String comments) 把Properties中的Key-value输出到指定的属性文件中,以输出流显示。

    package Test01;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Properties;
    
    public class TestProperties {
      public static void main(String[] args) throws FileNotFoundException, IOException {
        Properties properties =new Properties();
        properties.setProperty("a", "今天");
        properties.setProperty("b", "天气");
        properties.store(new FileOutputStream("a.ini"), "contrm");
        System.out.println(properties.getProperty("a"));
        Properties prop2 =new Properties();
        prop2.setProperty("c", "不错");
        prop2.load(new FileInputStream("a.ini"));
        System.out.println(prop2);
    }
    }
     比较HashSet与HashMap的性能选项:

    hashSet和其子类都是靠hash算法来决定集合元素的存储位置,并控制集合的大小。

    对于Hashtable和HashMap和子类来说,采用hash算法决定Map中key的存储,可增加Key集合大小。

    hash表里可以存储元素的位置被称为“桶”,单个桶存储一个元素是有最好的性能。

    通过hashcode值算出桶的存储位置。接着从桶里取出元素。

    但是hash表是open 的,发生hash冲突时单个桶可以存储多个元素,元素以链表形式存储,必须按顺序搜索。

    hash表有以下属性:

    容量:hash表的桶的数量

    初始化容量:创建hash表时桶的数量,在构造器中指定初始化容量。 

    尺寸:当前hash表记录的数量。

    负载因子:为0表示空的hash表,0.5表示半满的。轻负载的hash表表示冲突少,适合插入和查询。

    还有个负载极限:决定最大填满程度,达到负载极限时自动的成倍增加容量。将原有的对象重新分配 ,放入新的桶里,叫做rehashing.较低的负载极限可以提高查询数据的性能,但会增加hash表

    所占用的内存的开销。


    如果最开始就知道HashSet和HashMap Hashtable会保存许多记录,就在创建时用较大的初始化容量。初始化容量大于 包含的最大记录数除以负载极限就不会rehashing.

    使用足够大的初始化容量能更高效得增加记录。但是太高会浪费空间。
     
     
    对比下:
    WeakHashMap实现类

    与hashMap基本相似,但是区别在于HashMap的Key保留了对实际对象的强引用。意思就是:只要该HashMap对象不销毁,所有的key引用的对象就不会被垃圾销毁。

    但是WeakHashMap对象的key引用的对象没有被其他强引用变量引用,则这些key引用的对象就可能被垃圾回收。举例子:

    .....

    IdentityHashMap实现类

    实现机制与HashMap基本类似。但是对于Key的判断相等不同。IdentityHashMap key===(查下资料)才等,而HashMap equals为true,且hashcode值相等即可。

    ,举例
    .....
  • 相关阅读:
    《七哥说道》第十八章:何处不风雨,套路说江湖
    《七哥说道》第十七章:北漂青年,人海茫茫
    《闲扯Redis四》List数据类型底层编码转换
    《闲扯Redis三》Redis五种数据类型之List型
    《闲扯Redis二》String数据类型之底层解析
    《闲扯Redis一》五种数据类型之String型
    Js解析Json数据获取元素JsonPath与深度
    《七哥说道》第十六章:程序员,江湖见
    Swagger2.9.2进入API界面报NumberFormatException异常
    绝顶高手必经之路【资源共享】
  • 原文地址:https://www.cnblogs.com/yizhizhangBlog/p/9271849.html
Copyright © 2011-2022 走看看