在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的基本功能如下:

 public class TestMapBasic {

     public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
//添加键值对,value可重复
map.put("AAA", 110);
map.put("BBB", 120);
map.put("CCC", 20);
map.put("DDD", 120);
//添加重复key的时候,value会覆盖旧值,方法返回旧值
System.out.println(map.put("CCC", 111));
System.out.println(map);
//通过key和value查找是否存在对应的键\值
System.out.println("map.containsKey(\"BBB\")?: " + map.containsKey("BBB"));
System.out.println("map.containsValue(110)?: " + map.containsValue(110));
//遍历Map的增强for循环
for(String key:map.keySet()) {
System.out.println(key + "-->" + map.get(key));
}
//根据key删除value
map.remove("AAA");
System.out.println(map);
}
}

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

 public class TestMapAdvance {

     public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
//添加键值对,value可重复
map.put("AAA", 110);
map.put("BBB", 120);
map.put("CCC", 20);
map.put("DDD", 120);
//因为map中无ZZZ,因此替换失败
map.replace("ZZZ", 122);
System.out.println(map);
//使用原value与参入参数重新计算value
map.merge("CCC", 20, (oldVal, param) -> (oldVal+param)*2);
System.out.println(map);
//当key为Java,对应的value不存在或null, 计算结果为新value
map.computeIfAbsent("Java", (key) -> key.length());
System.out.println(map);
//当key为Java存在, 则用新结果替换
map.computeIfPresent("Java", (key, value) -> value * 100);
System.out.println(map);
}
}

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等应用场景中。

 public class TestProperties {

     public static void main(String[] args) throws FileNotFoundException, IOException {
Properties props = new Properties();
//为Properties对象添加元素
props.setProperty("username", "admin");
props.setProperty("password", "123456");
//写入文件
props.store(new FileOutputStream("test.properties"), "comment line");
Properties props2 = new Properties();
props2.setProperty("gender", "male");
//将文件中的内容追加到Props2的元素中
props2.load(new FileInputStream("test.properties"));
System.out.println(props2);
} }

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的方法。

 class R implements Comparable<Object>{

     int count;

     public R(int count) {
super();
this.count = count;
} @Override
public String toString() {
return "R [count=" + count + "]";
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
R other = (R) obj;
if (count != other.count)
return false;
return true;
} @Override
public int compareTo(Object o) {
R r = (R)o;
return count > r.count ? 1: count < r.count ? -1 : 0;
}
} public class TestTreeMap { public static void main(String[] args) {
TreeMap<R, String> tm = new TreeMap<>();
tm.put(new R(3), "AAAA");
tm.put(new R(-5), "BBB");
tm.put(new R(9), "CCCCCC");
System.out.println(tm);
//返回第一个Entry对象
System.out.println(tm.firstEntry());
//返回最后一个Key
System.out.println(tm.lastKey());
//返回比R(2)大一个的Key
System.out.println(tm.higherKey(new R(2)));
//返回比R(2)小的一个Key
System.out.println(tm.lowerKey(new R(2)));
//获取子串
System.out.println(tm.subMap(new R(-1), new R(4)));
System.out.println(tm);
}
}

WeakHashMap

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

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

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

 public class TestWeakHashMap {

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

IdentityHashMap

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

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

 public class TestIdentityHashMap {

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

总结

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

Java容器深入浅出之Map、HashMap、Hashtable及其它实现类的更多相关文章

  1. Java基础系列 - JAVA集合ArrayList,Vector,HashMap,HashTable等使用

    package com.test4; import java.util.*; /** * JAVA集合ArrayList,Vector,HashMap,HashTable等使用 */ public c ...

  2. Collections+Iterator 接口 | Map+HashMap+HashTable+TreeMap |

    Collections+Iterator 接口 1. Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询 ...

  3. Java 容器(list, set, map)

    java容器类库的简化图: (虚线框表示接口, 实线框表示普通的类, 空心箭头表示特定的类实现了接口, 实心箭头表示某个类可以生成箭头所指的类对象) 继承Collection的主要有Set 和 Lis ...

  4. [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

    注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...

  5. Java中ArrayList,Vector,LinkedList,HashMap,HashTable,HashSet对比及总结

    1.所有的集合的父类都是Collection的接口 2.Set List Map 区别 A  在Set里面:无法添加元素的顺序,所以Set里面的元素不能重复 B  在List中:有索引号,类似于数组, ...

  6. Java容器解析系列(11) HashMap 详解

    本篇我们来介绍一个最常用的Map结构--HashMap 关于HashMap,关于其基本原理,网上对其进行讲解的博客非常多,且很多都写的比较好,所以.... 这里直接贴上地址: 关于hash算法: Ha ...

  7. Java容器深入浅出之Collection与Iterator接口

    Java中用于保存对象的容器,除了数组,就是Collection和Map接口下的容器实现类了,包括用于迭代容器中对象的Iterator接口,构成了Java数据结构主体的集合体系.其中包括: 1. Co ...

  8. Java容器深入浅出之HashSet、TreeSet和EnumSet

    Java集合中的Set接口,定义的是一类无顺序的.不可重复的对象集合.如果尝试添加相同的元素,add()方法会返回false,同时添加失败.Set接口包括3个主要的实现类:HashSet.TreeSe ...

  9. Java容器深入浅出之数组

    写在前面 关于Java的学习,特别是对于非计算机专业的同学来说,我总是主张从实践中来,到实践中去的学习方法.Java本身是一门应用性特别强的高级编程语言,因此如果能在基于实际开发的经验基础上,对Jav ...

随机推荐

  1. 非局部均值滤波算法的python实现

    如题,比opencv自带的实现效果好 #coding:utf8 import cv2 import numpy as np def psnr(A, B): return 10*np.log(255*2 ...

  2. Storm 第四章 Storm常见问题

    1.集群如何启动,任务如何执行? java -server nimbus,supervisor client--->createTopology(序列化)--->提交jar到nimbusi ...

  3. Jenkins + Gitlab + Ansible--playbook 代码上线流程(文末有免费视频)

      jenkins 构建是支持 git 选择分支 安装 Git Parameter 插件在系统管理中的插件管理 然后点击选插件,在右上角输入 Git Parameter,找到 Git Paramete ...

  4. 如何让mysql按照两个或多个字段排序

    我准备设计一个供求信息的表格,里边包含序号(id)(自动增量),发布日期(time),上次更新(last_time).因为考虑到避免有人不停的重复发布信息来占据前列位置所以设置了last_time这个 ...

  5. Linux 安装JDK Tomcat MySQL(使用Mac远程访问)

    阅读本文需要一定的Linux基础 一 环境 阿里云服务器: CentOS 7.4 64位(基于RedHat) 本机: macOS High Sierra 二 压缩包 JDK http://www.or ...

  6. Unity生成简易二维码

    最近项目需求,需要在Unity中动态生成二维码.所以就研究了一下,下面把动态生成二维码的方法向大家分享一下. 第一种方法 需要一个 ZXing.dll文件. 下载地址我会在文章结尾给出. 直接将下载好 ...

  7. Netty源码分析第5章(ByteBuf)---->第1节: AbstractByteBuf

    Netty源码分析第五章: ByteBuf 概述: 熟悉Nio的小伙伴应该对jdk底层byteBuffer不会陌生, 也就是字节缓冲区, 主要用于对网络底层io进行读写, 当channel中有数据时, ...

  8. 第十三次作业psp

    psp 进度条 代码累积折线图 博文累积折线图 psp饼状图

  9. 第十二次作业psp

    psp 进度条 代码累积折线图 博文累积折线图 psp饼状图

  10. Scrum Meeting 11.1

    成员 今日任务 明日计划 用时 徐越 学习利用servlet上传下载文件 代码迁移 4h 赵庶宏 数据库的连接及代码学习 数据库连接 2h 武鑫 设计界面;尝试写一些初步的代码,独立完成一些简单界面 ...