Java Map集合

Map集合

Map集合用于保存映射关系的数据,Map集合中保存了两组值,一组是 key, 一组是 value。
Map的key不能重复。
key和value之间存在单向一对一的关系, 通过key,能找到唯一的,确定的value。

public interface Map<K,V> {
    // Query Operations
}

Map的key放在一起来看,组成了一个Set集合,value又类似于一个List集合。
Map接口中定义了如下常用方法:

  • clear():删除Map中所有的 key-value对
  • containsKey():是否包含指定的key
  • containsValue(): 是否包含一个或多个value。
  • entrySet(): 返回包含的 key-value对组成的Set集合,每个集合元素都是Map.Entry对象, Entry是Map的内部类。
  • get():返回指定key对应的value。
  • isEmpty(): 是否为空
  • keySet(): 返回key组成的Set集合
  • put(): 添加一个key-value对,如果存在,覆盖以前的
  • putAll(): 指定Map中复制过来
  • remove():删除指定key,或 key-value。
  • size():返回个数
  • values():返回所有 value组成的 Collection。
    JAVA 8 新增方法:
  • compute(): 根据第二个参数重新计算,并设置value
  • computeIfAbsent(): 同上,value为 Null时计算
  • computeIfPresent(): 同上, value不为Null时计算
  • forEach(): 遍历Map
  • merge(): value为null时,用传入的value覆盖,不为null时,重新计算覆盖
  • putIfAbsent(): value为null时覆盖
  • replace():key不存在时,不添加
  • replaceAll(): 重新计算key-value, 覆盖value。

Map中包含一个内部接口 Entry。
封装了一个key-value对。包含下面方法。

  • getKey(): 返回key
  • getValue(): 返回value
  • setValue(): 重新设置value
        Map map = new HashMap();
        map.put("A", 100);
        map.put("B", 90);
        map.put("C", 110);
        System.out.println(map);

        //D 不存在,不会改变
        map.replace("D", 80);
        System.out.println(map);

        //重新计算A
        map.merge("A", 20, (oldVal, newVal) -> (Integer)oldVal  + (Integer) newVal);
        System.out.println(map);

        //遍历
        map.forEach((key, value) -> System.out.println("key : " + key + " , value:" + value));

        //D 不存在,不存在时计算
        map.computeIfAbsent("D", (key) -> ((String) key).length());
        System.out.println(map);

        //D存在了, 存在计算
        map.computeIfPresent("D", (key, value) -> ((String) key).length() * 10);
        System.out.println(map);
//Output
{A=100, B=90, C=110}
{A=100, B=90, C=110}
{A=120, B=90, C=110}
key : A , value:120
key : B , value:90
key : C , value:110
{A=120, B=90, C=110, D=1}
{A=120, B=90, C=110, D=10}

HashMap和Hashtable

HashMap和Hashtable是Map接口的实现类。

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
}

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
}

Hashtable是古老的Map实现类,命名上都没有遵守JAVA命名规范,单词首字母大写。
JAVA 8改进了HashMap的实现,使用HashMap存在key冲突时也有较好的性能。
Hashtable 和 HashMap区别:
Hashtable 是线程安全的, HashMap是线程不安全的。
Hashtable 使用 null作为key和value, HashMap可以使用null作为key或value。 由于key不能重复, 最多只能有一个key为null。
Hashtable 比较古老,性能较差, 不推荐使用,
为了线程安全,可以使用 Collections 工具类。

        HashMap hashMap = new HashMap();
        hashMap.put("a", null);
        hashMap.put(null, null);
        hashMap.put(null, null);
        System.out.println(hashMap);
//Output
{null=null, a=null}

HashMap 同 HashSet, 判断两个key相等标准也是: 两个key通过 equals方法返回true, hashCode()也相等。

同HashSet, 可变对象最为HashMap的key, 程序如果修改了对象,程序无法准确的访问Map中的被修改的key。

class AA{
    int count;
    public AA(int count){
        this.count = count;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj == this)
            return true;
        if(obj != null && obj.getClass() == AA.class){
            AA a = (AA) obj;
            return a.count == this.count;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.count;
    }
}

public class MapTest {
    public static void main(String[] args){
        HashMap hashMap = new HashMap();
        hashMap.put(new AA(100), "A");
        hashMap.put(new AA(200), "B");
        Iterator iterator = hashMap.keySet().iterator();
        AA aa = (AA) iterator.next();
        aa.count = 200;
        System.out.println(hashMap);
        //只能删除没有被修改过key的
        hashMap.remove(new AA(200));
        System.out.println(hashMap);

        //无法获取剩下的value
        System.out.println(hashMap.get(new AA(200)));
        System.out.println(hashMap.get(new AA(100)));
   }
}
//Output
{testCode.AA@c8=A, testCode.AA@c8=B}
{testCode.AA@c8=A}
null
null

尽量不要使用可变对象作为 HashMap, Hashtable 的key, 如果使用,尽量不要修改作为key的可变对象。

LinkedHashMap实现类

LinkedHashMap 是 HashMap的子类。
LinkedHashMap使用双向链表维护key-value的次序。使迭代顺序和插入顺序一致。

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{

}
        LinkedHashMap linkedHashMap = new LinkedHashMap();
        linkedHashMap.put("A", 100);
        linkedHashMap.put("B", 200);
        linkedHashMap.put("C", 300);
        linkedHashMap.forEach((key, value) -> System.out.println(key + " ---> " + value));
//Output
A ---> 100
B ---> 200
C ---> 300

Properties

Properties 是 Hashtable 的子类。

public
class Properties extends Hashtable<Object,Object> {

}

可以方便的处理属性文件。
可以把属性文件,如 ini 中 属性名=属性值 加载到Map对象中。
Properties 相当于 key, value都是 String类型的Map。
主要有以下方法:

  • getProperty(): 获取属性值, 可以有 defaultValue。
  • setProperty(): 设置属性值
  • load():从属性文件中加载到 Properties里
  • store():输出到指定文件

下面是使用:

        Properties properties = new Properties();
        properties.setProperty("name", "liu");
        properties.setProperty("age", "20");
        System.out.println(properties);

        properties.store(new FileOutputStream("p.ini"), "comment");

        Properties properties1 = new Properties();
        properties1.load(new FileInputStream("p.ini"));
        System.out.println(properties1);
//Output
{age=20, name=liu}
{age=20, name=liu}

根目录下生成 p.ini文件

#comment
#Wed Feb 06 18:24:46 CST 2019
age=20
name=liu

TreeMap

TreeMap 是 SortedMap接口的实现类。

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
}

public interface NavigableMap<K,V> extends SortedMap<K,V> {
}

public interface SortedMap<K,V> extends Map<K,V> {
}

TreeMap是根据 key来排序, 就是一个红黑树数据结构,每个key-value对是一个红黑树节点。保证所有的key-value对处于有序状态。

同 TreeSet , 也有两种排序方法:
自然排序
定制排序。
排序判断标准是根据 compareTo() 方法的返回值。
主要方法包括: 取第一个, 最后一个, 前一个,后一个等 key-value对。 Map.Entry。

WeakHashMap

WeakHashMap 是 Map的实现类, 与HashMap基本相似.

public class WeakHashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V> {
}

HashMap的key保留了对实际对象的强引用,只要该HashMap对象不被销毁,该HashMap的所有key所引用的对象就不会被垃圾收集。
WeakHashMap 的key只保留了对实际对象的弱引用,该对象的key对所引用的对象没有被其他强引用对象所引用, 则key所引用的对象可能被垃圾回收,WeakHashMap也可能自动删除这些key所对应的key-value对。

        WeakHashMap weakHashMap = new WeakHashMap();
        //添加三个匿名字符串对象
        weakHashMap.put(new String("A"), 1);
        weakHashMap.put(new String("B"), 2);
        weakHashMap.put(new String("C"), 3);
        //添加key 系统缓存的字符串对象
        weakHashMap.put("java", 4);

        System.out.println(weakHashMap);
        System.gc();
        System.runFinalization();
        System.out.println(weakHashMap);
//Output
{java=4, C=3, B=2, A=1}
{java=4}

对于前三个匿名的字符串对象,WeakHashMap 保留了对他们的弱引用。垃圾回收时自动删除了这三个。
对于第四个 key是一个字符串直接量,系统自动保留了强引用,所以垃圾回收时不会回收它。

IdentityHashMap

IdentityHashMap是Map的实现类, 与HashMap基本相似.
他对处理两个 key相等时比较独特,当两个key严格相等时(key1 == key2).IdentityHashMap才认为两个key相等。
对于普通HashMap, 只要 equals返回TRUE, 且 hashCode值相等即可。

public class IdentityHashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, java.io.Serializable, Cloneable
{
}

测试例子:

        IdentityHashMap identityHashMap = new IdentityHashMap();
        identityHashMap.put(new String("A"), 1);
        identityHashMap.put(new String("A"), 2);
        identityHashMap.put("B", 3);
        identityHashMap.put("B", 4);
        System.out.println(identityHashMap);
//Output
{A=2, A=1, B=4}

前两个是新创建的字符串对象, == 为false,
后两个是字符串直接量,JAVA使用常量池管理字符串直接量, == 为true

EnumMap

EnumMap是与枚举类一起使用的Map。
key必须是单个枚举类的枚举值。

public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
    implements java.io.Serializable, Cloneable
{

}
  • EnumMap内部以数组形式保存,这种实现非常紧凑,高效
  • EnumMap根据key在枚举类中的定义的顺序,维护key-value顺序。
  • 不允许 null 作为key
    下面示例:
enum GenderEnum{
    MALE,FEMALE;
}
public class MapTest {
    public static void main(String[] args) throws  Exception{
        EnumMap enumMap = new EnumMap(GenderEnum.class);
        enumMap.put(GenderEnum.FEMALE, "女人");
        enumMap.put(GenderEnum.MALE, "男人");
        System.out.println(enumMap);
    }
}
//Output
{MALE=男人, FEMALE=女人}

FEMALE 先put, 但是输出还是按照枚举类中的定义顺序输出。

Map性能分析

HashMap 和 Hashtable 的实现机制几乎一样, Hashtable是一个古老的,线程安全的集合,因此 HashMap通常比Hashtable 性能好。
TreeMap是红黑树管理key-value对,一直是排序状态,性能比HashMap要慢。
LinkedHashMap比HashMap要慢, 需要链表来保持Map中的添加顺序。
EnumMap性能最好,使用同一个枚举类的枚举值为key。

性能选项

HashMap, HashSet 等通过 hash 算法决定Map中 key的存储。
hash 表里的存储元素的位置称为 桶,bucket。

  • 容量 capacity: hash表中桶的数量
  • 初始化容量 initial capacity: 创建 hash表时桶的数量
  • 尺寸 size: 当前 hash表中记录的数量
  • 负载因子(load factor):size/capacity. 0表示空hash表, 0.5表示半满的 hash表
    负载极限,表示hash表的最大填满程度,当负载因子达到负载极限时,进行 rehashing。 hash表会成倍的增加容量,桶的数量, 将原有的对象重新分配。
    负载极限默认值为 0.75。

地址: https://blog.csdn.net/yonggang7/article/details/86768876

发布了120 篇原创文章 · 获赞 46 · 访问量 29万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览