zoukankan      html  css  js  c++  java
  • Java容器深入浅出之Map、HashMap、Hashtable及其它实现类

    在Java中,Set的底层事实上是基于Map实现的,Map内部封装了一个Entry内部接口,由实现类来封装key-value对,当value值均为null时,key的集合就形成了Set。因此,Map集合具有如下的一些特点:

    1. Key集因为是Set的实现,因此是无顺序、不可重复的。

    2. Value集是List的实现,因此是可以重复的,每个元素根据key来索引。

    3. Map内部包含一个Entry内部接口,用于定义key-value对,由实现类来对外提供查找和设置value的方法。

    Map的基本功能如下:

     1 public class TestMapBasic {
     2 
     3     public static void main(String[] args) {
     4         Map<String, Integer> map = new HashMap<>();
     5         //添加键值对,value可重复
     6         map.put("AAA", 110);
     7         map.put("BBB", 120);
     8         map.put("CCC", 20);
     9         map.put("DDD", 120);
    10         //添加重复key的时候,value会覆盖旧值,方法返回旧值
    11         System.out.println(map.put("CCC", 111));
    12         System.out.println(map);
    13         //通过key和value查找是否存在对应的键值
    14         System.out.println("map.containsKey("BBB")?: " + map.containsKey("BBB"));
    15         System.out.println("map.containsValue(110)?: " + map.containsValue(110));
    16         //遍历Map的增强for循环
    17         for(String key:map.keySet()) {
    18             System.out.println(key + "-->" + map.get(key));
    19         }
    20         //根据key删除value
    21         map.remove("AAA");
    22         System.out.println(map);
    23     }
    24 }

    Map的Java8增强方法示例如下:

     1 public class TestMapAdvance {
     2 
     3     public static void main(String[] args) {
     4         Map<String, Integer> map = new HashMap<>();
     5         //添加键值对,value可重复
     6         map.put("AAA", 110);
     7         map.put("BBB", 120);
     8         map.put("CCC", 20);
     9         map.put("DDD", 120);
    10         //因为map中无ZZZ,因此替换失败
    11         map.replace("ZZZ", 122);
    12         System.out.println(map);
    13         //使用原value与参入参数重新计算value
    14         map.merge("CCC", 20, (oldVal, param) -> (oldVal+param)*2);
    15         System.out.println(map);
    16         //当key为Java,对应的value不存在或null, 计算结果为新value
    17         map.computeIfAbsent("Java", (key) -> key.length());
    18         System.out.println(map);
    19         //当key为Java存在, 则用新结果替换
    20         map.computeIfPresent("Java", (key, value) -> value * 100);
    21         System.out.println(map);
    22     }
    23 }

    HashMap和Hashtable

    HashMap和Hashtable都是Map接口的典型实现类,两者的区别在于:

    1. HashMap是线程不安全的,性能较高,可以使用null作为key或者value

    2. Hashtable是线程安全的,不可以用null做key和value。

    与HashSet一样,HashMap和Hashtable不能保证key-value对的顺序,判断两个元素是否相等的标准为:

    1. 两个key的equals方法比较返回true

    2. 两个key的HashCode方法值相同

    HashMap和Hashtable的containsValue()方法,用于判断是否包含指定的value,判断标准为两个value的equals方法相等即可。因此:

    1. 使用自定义类作为Key时,如果重写equals和HashCode方法,需确保判断标准一致。

    2. 尽量不要使用可变对象作为Key,如果确实需要则不要在程序中修改可变对象。

    LinkedHashMap

    LinkedHashMap在底层使用双链表来维护键值对的顺序,因而性能略低于HashMap,但在迭代集合元素时有较好的性能。

    Properties

    Properties是Hashtable的子类,相当于一个key和value都是String的Map。使用Properties可以方便地把属性文件的“属性名=属性值”转化为Map的键值对,还可以实现Map的键值对与XML文件之间的相互转化,广泛用于JDBC等应用场景中。

     1 public class TestProperties {
     2 
     3     public static void main(String[] args) throws FileNotFoundException, IOException {
     4         Properties props = new Properties();
     5         //为Properties对象添加元素
     6         props.setProperty("username", "admin");
     7         props.setProperty("password", "123456");
     8         //写入文件
     9         props.store(new FileOutputStream("test.properties"), "comment line");
    10         Properties props2 = new Properties();
    11         props2.setProperty("gender", "male");
    12         //将文件中的内容追加到Props2的元素中
    13         props2.load(new FileInputStream("test.properties"));
    14         System.out.println(props2);
    15     }
    16 
    17 }

    TreeMap

    TreeMap是SortedMap接口的实现类,同时也是TreeSet类的底层实现模型。因此具有与TreeSet相似的性质:

    1. TreeMap底层由红黑树的数据结构所实现,每个键值对即为红黑树的一个节点。TreeMap存储键值对时,需要根据Key对节点进行排序。

    2. TreeMap的排序方式包括两种:

    2.1 自然排序:通过Key所实现的Comparable接口来实现,要求Key都是同一个类的对象

    2.2 定制排序:创建TreeMap时,传入一个Comparator对象,负责对Key元素进行排序。

    3. 如果使用自定义类作为Key,重写该类的equals方法和compareTo方法应该一致:equals方法返回true时,compareTo方法要返回0。

    与HashSet相似,HashMap因为存储的键值对是有序的,因此提供了访问第一个、前一个、第一个、最后一个键值对的方法,以及若干截取子TreeMap的方法。

     1 class R implements Comparable<Object>{
     2     
     3     int count;
     4 
     5     public R(int count) {
     6         super();
     7         this.count = count;
     8     }
     9 
    10     @Override
    11     public String toString() {
    12         return "R [count=" + count + "]";
    13     }
    14 
    15     @Override
    16     public boolean equals(Object obj) {
    17         if (this == obj)
    18             return true;
    19         if (obj == null)
    20             return false;
    21         if (getClass() != obj.getClass())
    22             return false;
    23         R other = (R) obj;
    24         if (count != other.count)
    25             return false;
    26         return true;
    27     }
    28 
    29     @Override
    30     public int compareTo(Object o) {
    31         R r = (R)o;
    32         return count > r.count ? 1: count < r.count ? -1 : 0;
    33     }
    34 }
    35 
    36 public class TestTreeMap {
    37 
    38     public static void main(String[] args) {
    39         TreeMap<R, String> tm = new TreeMap<>();
    40         tm.put(new R(3), "AAAA");
    41         tm.put(new R(-5), "BBB");
    42         tm.put(new R(9), "CCCCCC");
    43         System.out.println(tm);
    44         //返回第一个Entry对象
    45         System.out.println(tm.firstEntry());
    46         //返回最后一个Key
    47         System.out.println(tm.lastKey());
    48         //返回比R(2)大一个的Key
    49         System.out.println(tm.higherKey(new R(2)));
    50         //返回比R(2)小的一个Key
    51         System.out.println(tm.lowerKey(new R(2)));
    52         //获取子串
    53         System.out.println(tm.subMap(new R(-1), new R(4)));
    54         System.out.println(tm);    
    55     }
    56 }
    View Code

    WeakHashMap

    WeakHashMap与HashMap的用法基本相似,区别在于:

    1. HashMap的Key保留的是对实际对象的强引用,只要HashMap对象不销毁,所有Key引用对象就不会被垃圾回收;HashMap也不会自动删除这些Key的键值对。

    2. WeakHashMap的Key保留的是对实际对象的弱引用,意味着如果这些Key没有被其它强引用对象所引用,Key对象可能会被垃圾回收;WeakHashMap对象也可能会删除这些键值对。

     1 public class TestWeakHashMap {
     2 
     3     public static void main(String[] args) {
     4         WeakHashMap<String, String> whm = new WeakHashMap<>();
     5         //添加的三个Key对象都是弱引用的匿名类对象
     6         whm.put(new String("Python"), new String("pass"));
     7         whm.put(new String("R"), new String("good"));
     8         whm.put(new String("Scala"), new String("great"));
     9         //添加一个系统缓存的字符串直接量, 为强引用对象,作为Key
    10         whm.put("Java", new String("Number One"));
    11         System.out.println(whm);
    12         //通知系统进行垃圾回收
    13         System.gc();
    14         System.runFinalization();
    15         //此时whm仅保留一个强引用的Java键值对
    16         System.out.println(whm);
    17     }
    18 }

    IdentityHashMap

    IdentityHashMap与HashMap的基本性质和用法大致相同,如可以添加null元素,存储元素的无序性等。核心区别在于判断两个Key对象的标准:

    IdentityHashMap严格要求两个Key必须是Key1 == Key2的严格相等,即堆内存地址相同。

     1 public class TestIdentityHashMap {
     2 
     3     public static void main(String[] args) {
     4         IdentityHashMap<String, Integer> ihm = new IdentityHashMap<>();
     5         //两个new String对象,会被认为是不同的Key,一起添加到集合中
     6         ihm.put(new String("Python"), 100);
     7         ihm.put(new String("Python"), 98);
     8         //字符串直接量Java的内存地址相同,会被认为是同一个对象, 因此只会添加一个(覆盖前值)
     9         ihm.put("Java", 100);
    10         ihm.put("Java", 11);
    11         System.out.println(ihm);
    12     }
    13 }

    总结

    一般的使用中,为了获取较方便的快速查询,使用HashMap较多。特别地,如果需要一个总是排好序的Key-Value集合,则考虑TreeMap。通过TreeMap的KeySet可以直接获取Key集合,然后通过Arrays的工具类转为数组,就可以通过二分法快速查找已经排序完成的对象。

  • 相关阅读:
    Spring 中出现Element : property Bean definitions can have zero or more properties. Property elements correspond to JavaBean setter methods exposed by the bean classes. Spring supports primitives, refer
    java定时器schedule和scheduleAtFixedRate区别
    hql语句中的select字句和from 字句
    使用maven搭建hibernate的pom文件配置
    Failure to transfer org.apache.maven:maven-archiver:pom:2.5 from http://repo.maven.apache.org/ maven2 was cached in the local repository, resolution will not be reattempted until the update interv
    对于文件File类型中的目录分隔符
    hibernate的事务管理和session对象的详解
    解决mac 中的myeclipse控制台中文乱码问题
    ibatis selectKey用法问题
    Java中getResourceAsStream的用法
  • 原文地址:https://www.cnblogs.com/leoliu168/p/9910253.html
Copyright © 2011-2022 走看看