来自 电脑知识 2019-11-08 01:16 的文章
当前位置: 威尼斯国际官方网站 > 电脑知识 > 正文

Java中HashMap和TreeMap的区别深入理解

第一介绍一下怎么着是Map。在数组中大家是通过数组下标来对其内容索引的,而在Map中大家经过对象来对目的实行索引,用来索引的靶子叫做key,其对应的对象叫做value。那就是大家日常说的键值对。

HashMap通过hashcode对其内容打开急迅寻觅,而 TreeMap中全数的因素都保持着某种固定的依次,倘若您需求得到叁个静止的结果你就相应运用TreeMap(HashMap中元素的排列顺序是不固定的卡塔 尔(阿拉伯语:قطر‎。
HashMap 非线程安全 TreeMap 非线程安全

线程安全
在Java里,线程安全日常显示在四个方面:
1、多少个thread对同一个java实例的拜候(read和modify卡塔 尔(阿拉伯语:قطر‎不会相互压抑,它最首要体今后事关心注重大字synchronized。如ArrayList和Vector,HashMap和Hashtable
(后面一个各种方法前都有synchronized关键字卡塔 尔(阿拉伯语:قطر‎。假设您在interator一个List对象时,其余线程remove三个element,难题就涌出了。

2、每种线程都有投机的字段,而不会在八个线程之间共享。它最主要反映在java.lang.ThreadLocal类,而从不Java关键字援助,如像static、transient那样。
1.AbstractMap抽象类和SortedMap接口
AbstractMap抽象类:(HashMap世襲AbstractMap)覆盖了equals()和hashCode()方法以保障多少个十二分映射重回相近的哈希码。假如多个映射大小相等、饱含雷同的键且每一种键在这里七个映射中对应的值都生机勃勃致,则那三个映射相等。映射的哈希码是璀璨元素哈希码的总额,个中每一个成分是Map.Entry接口的一个贯彻。因而,不论映射内部顺序怎么着,八个非常映射会报告相像的哈希码。
SortedMap接口:(TreeMap世襲自SortedMap卡塔尔它用来保持键的稳步次第。SortedMap接口为影象的视图(子集),包含五个端点提供了会见方法。除了排序是功用于映射的键以外,管理SortedMap和管理SortedSet肖似。增添到SortedMap完结类的要素必需落实Comparable接口,不然你必得给它的构造函数提供多少个Comparator接口的贯彻。TreeMap类是它的唯生龙活虎黄金时代份完成。

2.三种常规Map达成
HashMap:基于哈希表完成。使用HashMap要求加上的键类鲜明概念了hashCode()和equals()[能够重写hashCode()和equals()],为了优化HashMap空间的采取,您能够调优开首体积和负载因子。
(1)HashMap(): 创设多少个空的哈希影象
(2)HashMap(Map m): 塑造二个哈希影象,并且增进影象m的具有映射
(3)HashMap(int initialCapacity): 营造贰个有所一定体积的空的哈希印象
(4)HashMap(int initialCapacity, float loadFactor): 创设二个兼有一定体量和加载因子的空的哈希印象
TreeMap:基于红黑树完结。TreeMap未有调优选项,因为该树总处于平衡景况。
(1)TreeMap():营造四个空的影像树
(2)TreeMap(Map m): 营造一个印象树,何况增加影象m中全数因素
(3)TreeMap(Comparator c): 营造八个影像树,并且动用一定的相比较器对首要字展开排序
(4)TreeMap(SortedMap s): 创设贰个影像树,加多影像树s中兼有映射,而且动用与平稳印象s雷同的相比较器排序

3.三种常规Map品质
HashMap:适用于在Map中插入、删除和一直成分。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。

4.总结
HashMap日常比TreeMap快一点(树和哈希表的数据结构使然),提出多选用HashMap,在急需排序的Map时候才用TreeMap。

复制代码 代码如下:

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class HashMaps {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("a", "aaa");
map.put("b", "bbb");
map.put("c", "ccc");
map.put("d", "ddd");
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println("map.get(key) is :" + map.get(key));
}
// 定义HashTable,用来测量检验
Hashtable<String, String> tab = new Hashtable<String, String>();
tab.put("a", "aaa");
tab.put("b", "bbb");
tab.put("c", "ccc");
tab.put("d", "ddd");
Iterator<String> iterator_1 = tab.keySet().iterator();
while (iterator_1.hasNext()) {
Object key = iterator_1.next();
System.out.println("tab.get(key) is :" + tab.get(key));
}
TreeMap<String, String> tmp = new TreeMap<String, String>();
tmp.put("a", "aaa");
tmp.put("b", "bbb");
tmp.put("c", "ccc");
tmp.put("d", "cdc");
Iterator<String> iterator_2 = tmp.keySet().iterator();
while (iterator_2.hasNext()) {
Object key = iterator_2.next();
System.out.println("tmp.get(key) is :" + tmp.get(key));
}
}
}

运维结果如下:
map.get(key) is :ddd
map.get(key) is :bbb
map.get(key) is :ccc
map.get(key) is :aaa
tab.get(key) is :bbb
tab.get(key) is :aaa
tab.get(key) is :ddd
tab.get(key) is :ccc
tmp.get(key) is :aaa
tmp.get(key) is :bbb
tmp.get(key) is :ccc
tmp.get(key) is :cdc
HashMap的结果是未有排序的,而TreeMap输出的结果是排好序的。
下边将要步入本文的核心了。先举个例证说澳优下什么利用HashMap:

复制代码 代码如下:

import java.util.*;
public class Exp1 {
public static void main(String[] args){
HashMap h1=new HashMap();
Random r1=new Random();
for (int i=0;i<1000;i++){
Integer t=new Integer(r1.nextInt(20));
if (h1.containsKey(t))
((Ctime)h1.get(t)).count++;
else
h1.put(t, new Ctime());
}
System.out.println(h1);
}
}
class Ctime{
int count=1;
public String toString(){
return Integer.toString(count);
}
}

在HashMap中通过get()来赢得value,通过put()来插入value,ContainsKey()则用来查看对象是还是不是业已存在。能够看看,和ArrayList的操作相比较,HashMap除了经过key索引其故事情节之外,另一方面差异并超级小。
眼下介绍了,HashMap是基于HashCode的,在颇负指标的超类Object中有叁个HashCode()方法,可是它和equals方法相近,并不可能适用于所有的场地,这样大家就供给重写自身的HashCode()方法。上边就举这样二个事例:

复制代码 代码如下:

import java.util.*;
public class Exp2 {
public static void main(String[] args){
HashMap h2=new HashMap();
for (int i=0;i<10;i++)
h2.put(new Element(i), new Figureout());
System.out.println("h2:");
System.out.println("Get the result for Element:");
Element test=new Element(5);
if (h2.containsKey(test))
System.out.println((Figureout)h2.get(test));
else
System.out.println("Not found");
}
}
class Element{
int number;
public Element(int n){
number=n;
}
}
class Figureout{
Random r=new Random();
boolean possible=r.nextDouble()>0.5;
public String toString(){
if (possible)
return "OK!";
else
return "Impossible!";
}
}

在这里个事例中,Element用来索引对象Figureout,也即Element为key,Figureout为value。在Figureout中随机生成一个浮点数,假如它比0.5大,打字与印刷"OK!",不然打字与印刷"Impossible!"。之后查看Element(3)对应的Figureout结果怎么样。

结果却开掘,无论你运维多少次,得到的结果都以"Not found"。也便是说索引Element(3)并不在HashMap中。那怎么大概啊?
案由得慢慢的话:Element的HashCode方法世袭自Object,而Object中的HashCode方法再次回到的HashCode对应于当前的地址,也等于说对于分裂的靶子,就算它们的内容完全雷同,用HashCode(卡塔尔重回的值也会不一致。那样实在违背了我们的用意。因为大家在应用 HashMap时,希望选用同意气风发内容的对象索引拿到相似的指标对象,那就需求HashCode()在这里时候能够回来相通的值。在地点的事例中,我们期望new Element(i) (i=5)与 Elementtest=newElement(5)是如出黄金年代辙的,而实质上那是七个例外的靶子,就算它们的原委相仿,但它们在内存中的地址分歧。因而很自然的,上边的次第得不到大家着想的结果。下边临Element类改正如下:

复制代码 代码如下:

class Element{
int number;
public Element(int n){
number=n;
}
public int hashCode(){
return number;
}
public boolean equals(Object o){
return (o instanceof Element) && (number==((Element)o).number);
}
}

在那地Element覆盖了Object中的hashCode()和equals()方法。覆盖hashCode()使其以number的值作为 hashcode重返,那样对于同样内容的靶子的话它们的hashcode也就同一了。而覆盖equals()是为着在HashMap判定八个key是否等于时使结果有意义(有关心珍视写equals()的剧情能够参照小编的另风流洒脱篇文章《重新编写Object类中的方法》卡塔尔。改良后的程序运转结果如下:
h2:
Get the result for Element:
Impossible!
请深深记住:假若您想有效的行使HashMap,你就亟须重写在其的HashCode()。
还会有两条重写HashCode()的标准:
[list=1]
不用对种种分裂的指标都发出三个唯生龙活虎的hashcode,只要你的HashCode方法使get()可以拿走put()放进去的剧情就能够了。即"不为后生可畏规格"。

生成hashcode的算法尽量使hashcode的值分散部分,不要过多hashcode都汇聚在二个节制内,那样便于升高HashMap的习性。即"分散原则"。至于第二条标准的求实原因,有兴趣者能够参照BruceEckel的《Thinking in Java》,在那有对HashMap内部达成原理的牵线,这里就不赘述了。
支配了这两条法则,你就能够用好HashMap编写自个儿的顺序了。不知底我们注意未有,java.lang.Object中提供的八个方式:clone(),equals()和hashCode()尽管很卓越,但在广大意况下都不能适用,它们只是简短的由对象之处得出结果。这就须要大家在大团结的主次中重写它们,其实java类库中也重写了许繁多多少个这么的办法。利用面向对象的多态性——覆盖,Java的设计者很温婉的创设了Java的构造,也更加的显示了Java是一门纯OOP语言的个性。

你大概感兴趣的篇章:

  • 基于Java中最常用的集结类框架之HashMap(精解)
  • Java集结框架源码剖析之LinkedHashMap详细解释
  • Java concurrency集合之ConcurrentHashMap_重力节点Java高校收拾
  • Java会集之HashMap用法详明
  • JAVA HashMap详细介绍和演示
  • 浅析Java中Map与HashMap,Hashtable,HashSet的区别
  • java HashMap通过value反查key的代码示例
  • Java中HashMap和Hashtable及HashSet的区别
  • java中Hashtable和HashMap的界别深入分析
  • Java集结连串之HashMap源码解析

本文由威尼斯国际官方网站发布于电脑知识,转载请注明出处:Java中HashMap和TreeMap的区别深入理解

关键词: