当前位置: 首页 > news >正文

HashMap vs. TreeMap vs. Hashtable vs.LinkedHashMap

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1. Map概览

Java SE中有四种常见的Map实现——HashMap, TreeMap, Hashtable和LinkedHashMap。如果我们使用一句话来分别概括它们的特点,就是:

  • HashMap就是一张hash表,键和值都没有排序。

  • TreeMap以红-黑树结构为基础,键值按顺序排列。

  • LinkedHashMap保存了插入时的顺序。

  • Hashtable是同步的(而HashMap是不同步的)。所以如果在线程安全的环境下应该多使用HashMap,而不是Hashtable,因为Hashtable对同步有额外的开销。


  • HashMap

  • 如果HashMap的键(key)是自定义的对象,那么需要按规则定义它的equals()和hashCode()方法。

  • class Dog {
        String color;
     
        Dog(String c) {
            color = c;
        }
        public String toString(){   
            return color + " dog";
        }
    }
     
    public class TestHashMap {
        public static void main(String[] args) {
            HashMap hashMap = new HashMap();
            Dog d1 = new Dog("red");
            Dog d2 = new Dog("black");
            Dog d3 = new Dog("white");
            Dog d4 = new Dog("white");
     
            hashMap.put(d1, 10);
            hashMap.put(d2, 15);
            hashMap.put(d3, 5);
            hashMap.put(d4, 20);
     
            //print size
            System.out.println(hashMap.size());
     
            //loop HashMap
            for (Entry entry : hashMap.entrySet()) {
                System.out.println(entry.getKey().toString() + " - " + entry.getValue());
            }
        }
    }

输出:

1
2
3
4
5
4
white dog - 5
black dog - 15
red dog - 10
white dog - 20

注意,我们错误的将”white dogs”添加了两次,但是HashMap却接受了两只”white dogs”。这不合理(因为HashMap的键不应该重复),我们会搞不清楚真正有多少白色的狗存在。

Dog类应该定义如下:

class Dog {
    String color;
 
    Dog(String c) {
        color = c;
    }
 
    public boolean equals(Object o) {
        return ((Dog) o).color == this.color;
    }
 
    public int hashCode() {
        return color.length();
    }
 
    public String toString(){   
        return color + " dog";
    }
}

现在输出结果如下:

1
2
3
4
3
red dog - 10
white dog - 20
black dog - 15

输出结果如上是因为HashMap不允许有两个相等的元素存在。默认情况下(也就是类没有实现hashCode()和equals()方法时),会 使用Object类中的这两个方法。Object类中的hashCode()对于不同的对象会返回不同的整数,而只有两个引用指向的同样的对象时 equals()才会返回true。如果你不是很了解hashCode()和equals()的规则,可以看看这篇文章。

来看看HashMap最常用的方法,如迭代、打印等。

3. TreeMap

TreeMap的键按顺序排列。让我们先看个例子看看什么叫作“键按顺序排列”。

package javaBasic;

import java.util.TreeMap;
import java.util.Map.Entry;

class Dog {
    String color;

    Dog(String c) {
        color = c;
    }

    public boolean equals(Object o) {
        return ((Dog) o).color == this.color;
    }

    public int hashCode() {
        return color.length();
    }

    public String toString() {
        return color + " dog";
    }
}

public class TreeMapTest {
    public static void main(String[] args) {
        Dog d1 = new Dog("red");
        Dog d2 = new Dog("black");
        Dog d3 = new Dog("white");
        Dog d4 = new Dog("white");

        TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
        treeMap.put(d1, 10);
        treeMap.put(d2, 15);
        treeMap.put(d3, 5);
        treeMap.put(d4, 20);

        for (Entry<Dog, Integer> entry : treeMap.entrySet()) {
            System.out.println(entry.getKey() + " - " + entry.getValue());
        }
    }
}

Exception in thread "main" java.lang.ClassCastException: javaBasic.Dog
    at java.util.TreeMap.compare(Unknown Source)
    at java.util.TreeMap.put(Unknown Source)
    at javaBasic.TreeMapTest.main(TreeMapTest.java:35)


因为TreeMap按照键的顺序进行排列对象,所以键的对象之间需要能够比较,所以就要实现Comparable接口。你可以使用String作为键,String已经实现了Comparable接口。

我们来修改下Dog类,让它实现Comparable接口。

package javaBasic;

import java.util.TreeMap;
import java.util.Map.Entry;

class Dog implements Comparable<Dog>{
    String color;
    int size;
 
    Dog(String c, int s) {
        color = c;
        size = s;
    }
 
    public String toString(){  
        return color + " dog";
    }
 
    
    public int compareTo(Dog o) {
        return  o.size - this.size;
    }

}

public class TreeMapTest {
    public static void main(String[] args) {
        Dog d1 = new Dog("red", 30);
        Dog d2 = new Dog("black", 20);
        Dog d3 = new Dog("white", 10);
        Dog d4 = new Dog("white", 10);

        TreeMap<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
        treeMap.put(d1, 10);
        treeMap.put(d2, 15);
        treeMap.put(d3, 5);
        treeMap.put(d4, 20);

        for (Entry<Dog, Integer> entry : treeMap.entrySet()) {
            System.out.println(entry.getKey() + " - " + entry.getValue());
        }
    }
}

输出:

1
2
3
red dog - 10
black dog - 15
white dog - 20

结果根据键的排列顺序进行输出,在我们的例子中根据size排序的。

如果我们将“Dog d4 = new Dog(“white”, 10);”替换成“Dog d4 = new Dog(“white”, 40);”,那么输出会变成:

white dog - 20
red dog - 10
black dog - 15
white dog - 5

这是因为TreeMap使用compareTo()方法来比较键值的大小,size不相等的狗是不同的狗。

4. Hashtable

Java文档写道:

HashMap类和Hashtable类几乎相同,不同之处在于HashMap是不同步的,也允许接受null键和null值。

5. LinkedHashMap

LinkedHashMap是HashMap的子类,所以LinkedHashMap继承了HashMap的一些属性,它在HashMap基础上增加的特性就是保存了插入对象的顺序。

class Dog {
    String color;
 
    Dog(String c) {
        color = c;
    }
 
    public boolean equals(Object o) {
        return ((Dog) o).color == this.color;
    }
 
    public int hashCode() {
        return color.length();
    }
 
    public String toString(){   
        return color + " dog";
    }
}
 
public class TestHashMap {
    public static void main(String[] args) {
 
        Dog d1 = new Dog("red");
        Dog d2 = new Dog("black");
        Dog d3 = new Dog("white");
        Dog d4 = new Dog("white");
 
        LinkedHashMap linkedHashMap = new LinkedHashMap();
        linkedHashMap.put(d1, 10);
        linkedHashMap.put(d2, 15);
        linkedHashMap.put(d3, 5);
        linkedHashMap.put(d4, 20);
 
        for (Entry entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + " - " + entry.getValue());
        }       
    }
}

red dog - 10
black dog - 15
white dog - 20

如果我们使用HashMap的话,输出将会如下,会打乱插入的顺序:.

package javaBasic;

import java.util.HashMap;
import java.util.Map.Entry;


/**
 * HashMap就是一张hash表,键和值都没有排序。
 * @author markGao
 *
 */
 
public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Dog, Integer> hashMap = new HashMap<Dog, Integer>();
        Dog d1 = new Dog("red");
        Dog d2 = new Dog("black");
        Dog d3 = new Dog("white");
        Dog d4 = new Dog("white");
 
        hashMap.put(d1, 10);
        hashMap.put(d2, 15);
        hashMap.put(d3, 5);
        hashMap.put(d4, 20);
 
        //print size
        System.out.println(hashMap.size());
 
        //loop HashMap
        //如果我们使用HashMap的话,输出将会如下,会打乱插入的顺序:
        for (Entry<Dog, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey().toString() + " - " + entry.getValue());
        }
    }
}
1
2
3
red dog - 10
white dog - 20
black dog - 15


转载于:https://my.oschina.net/u/1412027/blog/195220

相关文章:

  • 第二十二课:磁滞和麦克斯韦方程组
  • JOOMLA中文安装时 数据库发生错误解块办法
  • haproxy介绍
  • 毕设问题小记——Spring事务配置
  • 对象.delegate=self的理解
  • vsftp虚拟用户配置
  • DevExpress控件使用系列--ASPxUploadControl(图片上传及预览)
  • linux 常用操作命令
  • Android 编程下背景图片适配工具类
  • javascript数组操作汇总
  • XVim的安装和卸载
  • Linux下C结构体初始化[总结]
  • linux环境搭建过程中遇到的问题
  • 我的北漂在路上--------时不时的停下脚步思考
  • Linux系统管理的基本入手点
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 4. 路由到控制器 - Laravel从零开始教程
  • Centos6.8 使用rpm安装mysql5.7
  • chrome扩展demo1-小时钟
  • Consul Config 使用Git做版本控制的实现
  • Django 博客开发教程 16 - 统计文章阅读量
  • Java多态
  • JS函数式编程 数组部分风格 ES6版
  • js中forEach回调同异步问题
  • Laravel核心解读--Facades
  • MD5加密原理解析及OC版原理实现
  • mongodb--安装和初步使用教程
  • React Native移动开发实战-3-实现页面间的数据传递
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • Web标准制定过程
  • 给第三方使用接口的 URL 签名实现
  • 关于Java中分层中遇到的一些问题
  • 缓存与缓冲
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 如何设计一个微型分布式架构?
  • 微服务入门【系列视频课程】
  • 线上 python http server profile 实践
  • 鱼骨图 - 如何绘制?
  • ​你们这样子,耽误我的工作进度怎么办?
  • #数学建模# 线性规划问题的Matlab求解
  • $.ajax()参数及用法
  • (4)logging(日志模块)
  • (day 12)JavaScript学习笔记(数组3)
  • (day6) 319. 灯泡开关
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (三)Honghu Cloud云架构一定时调度平台
  • (十一)图像的罗伯特梯度锐化
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .Net6使用WebSocket与前端进行通信