`

关于Map的九大问题, HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap

    博客分类:
  • Java
 
阅读更多
关于Map的九大问题 http://itxxz.iteye.com/blog/2102597
0、将Map转换为List类型

在java中Map接口提供了三种集合获取方式:Key set,,value set, and key-value set.。它们都可以通过构造方法或者addAll()方法来转换为List类型。下面代码就说明了如何从Map中构造ArrayList:
// key list
List keyList = new ArrayList(map.keySet());
// value list
List valueList = new ArrayList(map.valueSet());
// key-value list
List entryList = new ArrayList(map.entrySet());


1、通过Entry 遍历Map
java中这种以键值对存在的方式被称为Map.Entry。Map.entrySet()返回的是一个key-value 集合,这是一种非常高效的遍历方式。
for(Entry entry: map.entrySet()) {
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}


Iterator 我们也经常用到,尤其是在JDK1.5以前
Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
  Entry entry = itr.next();
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}


2、通过Key来对Map排序
排序需要对Map的ke进行频繁的操作,一种方式就是通过比较器(comparator )来实现:
List list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator() {
 
  @Override
  public int compare(Entry e1, Entry e2) {
    return e1.getKey().compareTo(e2.getKey());
  }
 
});

另外一种方法就是通过SortedMap,但必须要实现Comparable接口。
SortedMap sortedMap = new TreeMap(new Comparator() {
 
  @Override
  public int compare(K k1, K k2) {
    return k1.compareTo(k2);
  }
 
});
sortedMap.putAll(map);


3、对value对Map进行排序
这与上一点有些类似,代码如下:
List list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator() {
 
  @Override
  public int compare(Entry e1, Entry e2) {
    return e1.getValue().compareTo(e2.getValue());
  }
 
});




4、初始化一个static 的常量Map
当你希望创建一个全局静态Map的时候,我们有以下两种方式,而且是线程安全的。
而在Test1中,我们虽然声明了map是静态的,但是在初始化时,我们依然可以改变它的值,就像Test1.map.put(3,"three");
在Test2中,我们通过一个内部类,将其设置为不可修改,那么当我们运行Test2.map.put(3,"three")的时候,它就会抛出一个UnsupportedOperationException 异常来禁止你修改。
public class Test1 {
 
  private static final Map map;
  static {
    map = new HashMap();
    map.put(1, "one");
    map.put(2, "two");
  }
}

public class Test2 {
 
  private static final Map map;
  static {
    Map aMap = new HashMap();
    aMap.put(1, "one");
    aMap.put(2, "two");
    map = Collections.unmodifiableMap(aMap);
  }
}



5、HashMap, TreeMap, and Hashtable之间的不同
在Map接口中,共有三种实现:HashMap,TreeMap,Hashtable。
它们之间各有不同,详细内容请参考 HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap. 一文。

6、Map中的反向查询
我们在Map添加一个键值对后,意味着这在Map中键和值是一一对应的,一个键就是对应一个值。但是有时候我们需要反向查询,比如通过某一个值来查找它的键,这种数据结构被称为bidirectional map,遗憾的是JDK并没有对其支持。
Apache和Guava 共同提供了这种bidirectional map实现,它在实现中它规定了键和值都是必须是1:1的关系。

7、对Map的复制
java中提供了很多方法都可以实现对一个Map的复制,但是那些方法不见得会时时同步。简单说,就是一个Map发生的变化,而复制的那个依然保持原样。下面是一个比较高效的实现方法:
Map copiedMap = Collections.synchronizedMap(map);

当然还有另外一个方法,那就是克隆。但是我们的java鼻祖Josh Bloch却不推荐这种方式,他曾经在一次访谈中说过关于Map克隆的问题:在很多类中都提供了克隆的方法,因为人们确实需要。但是克隆非常有局限性,而且在很多时候造成了不必要的影响。(原文《Copy constructor versus cloning》)

8、创建一个空的Map
如果这个map被置为不可用,可以通过以下实现
map = Collections.emptyMap();

相反,我们会用到的时候,就可以直接
map = new HashMap();




HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap
http://www.itxxz.com/a/tea/2014/0811/192.html

Map是最重要的数据结构。这篇文章中,我会带你们看看HashMap, TreeMap, HashTable和LinkedHashMap的区别。

1. Map概览

Java SE中有四种常见的Map实现——HashMap, TreeMap, Hashtable和LinkedHashMap。如果我们使用一句话来分别概括它们的特点,就是:
HashMap就是一张hash表,键和值都没有排序
TreeMap以红-黑树结构为基础,键值按顺序排列
LinkedHashMap保存了插入时的顺序
Hashtable同步的(而HashMap是不同步的)。所以如果在线程安全的环境下应该多使用HashMap,而不是Hashtable,因为Hashtable对同步有额外的开销。

2. 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<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
		for (Entry<Dog, Integer> entry : hashMap.entrySet()) {
			System.out.println(entry.getKey().toString() + " - " + entry.getValue());
		}
	}
}


输出:

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";
	}
}


现在输出结果如下:

3
red dog - 10
white dog - 20
black dog - 15
输出结果如上是因为HashMap不允许有两个相等的元素存在。默认情况下(也就是类没有实现hashCode()和equals()方法时),会使用Object类中的这两个方法。Object类中的hashCode()对于不同的对象会返回不同的整数,而只有两个引用指向的同样的对象时equals()才会返回true。。

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

3. TreeMap

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


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 TestTreeMap {
	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: collection.Dog cannot be cast to java.lang.Comparable
at java.util.TreeMap.put(Unknown Source)
at collection.TestHashMap.main(TestHashMap.java:35)
因为TreeMap按照键的顺序进行排列对象,所以键的对象之间需要能够比较,所以就要实现Comparable接口。你可以使用String作为键,String已经实现了Comparable接口。

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


class Dog implements Comparable<Dog>{
	String color;
	int size;
 
	Dog(String c, int s) {
		color = c;
		size = s;
	}
 
	public String toString(){	
		return color + " dog";
	}
 
	@Override
	public int compareTo(Dog o) {
		return  o.size - this.size;
	}
}
 
public class TestTreeMap {
	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());
		}
	}
}


输出:

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 is a subclass of HashMap. That means it inherits the features of HashMap. In addition, the linked list preserves the insertion-order.

Let’s replace the HashMap with LinkedHashMap using the same code used for HashMap.

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<Dog, Integer> linkedHashMap = new LinkedHashMap<Dog, Integer>();
		linkedHashMap.put(d1, 10);
		linkedHashMap.put(d2, 15);
		linkedHashMap.put(d3, 5);
		linkedHashMap.put(d4, 20);
 
		for (Entry<Dog, Integer> entry : linkedHashMap.entrySet()) {
			System.out.println(entry.getKey() + " - " + entry.getValue());
		}		
	}
}

输出:


red dog - 10
black dog - 15
white dog - 20
如果我们使用HashMap的话,输出将会如下,会打乱并插入的顺序:
red dog - 10
white dog - 20
black dog - 15
分享到:
评论

相关推荐

    java中HashMap,LinkedHashMap,TreeMap,HashTable的区别

    本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, `TreeMap`以及`HashTable`之间的区别。 #### 1. HashMap `HashMap`是一种基于哈希表实现的`Map`接口,提供了一个非同步的、允许使用`null`键和...

    HashMap,HashTable,LinkedHashMap,TreeMap的区别

    其中,HashMap, HashTable, LinkedHashMap, TreeMap 是四种常用的 Map 实现类,每种类都有其特点和用途。本文将对这四种 Map 实现类进行比较和分析。 HashMap HashMap 是 Java 中最常用的 Map 实现类,它根据键的 ...

    HashMap vs TreeMap vs Hashtable vs LinkedHashMap

    for (Map.Entry, Integer&gt; entry : linkedHashMap.entrySet()) { System.out.println(entry.getKey() + " - " + entry.getValue()); } ``` 在上面的示例中,元素将按照它们被插入的顺序打印出来。 总结 HashMap是...

    java HashMap,TreeMap与LinkedHashMap的详解

    在Java编程语言中,`HashMap`、`TreeMap`和`LinkedHashMap`都是`java.util.Map`接口的实现,它们提供了不同的数据存储和访问策略。本文将深入探讨这三种数据结构的特点、工作原理以及适用场景。 1. **HashMap** `...

    第9讲 对比Hashtable、HashMap、TreeMap有什么不同?1

    了解Map的整体结构也很重要,HashMap和其他Map实现如LinkedHashMap(保持插入顺序或访问顺序的HashMap)都是从AbstractMap继承,而Hashtable则直接继承Dictionary类,这反映了它们设计上的差异和适用场景的不同。...

    Map集合的继承关系图.pdf

    5. ConcurrentHashMap:这个类是为了解决HashMap线程不安全的问题而设计的,并且提供了比Hashtable更好的并发性能。在Java 5及以上版本中得到了改进,提供了一些线程安全的方法。 6. WeakHashMap:这个实现与...

    Java集合专题总结:HashMap 和 HashTable 源码学习和面试总结

    Map接口用于保存具有key-value映射关系的数据,常见的Map实现包括HashMap、TreeMap、HashTable和LinkedHashMap等。Queue是Java提供的队列实现。 本文总结了HashMap和HashTable的源码学习和面试总结,涵盖了它们的...

    HashMapvs.TreeMapvs.Hashtable

    在Java编程语言中,`HashMap`、`TreeMap`和`Hashtable`是三种常见的集合类,它们都实现了`Map`接口,用于存储键值对数据。理解这些类的区别和应用场景对于提升Java开发技能至关重要。 首先,`HashMap`是Java中最...

    HashMap底层原理.pdf

    首先,HashMap是基于哈希表的Map接口非同步实现,它允许使用null值和null键,这意味着HashMap在设计时没有考虑多线程环境下的线程安全问题。在单线程环境下,HashMap提供了优秀的性能和访问速度。而如果需要线程安全...

    程序员需要经常刷题吗-simple-java-zh-CN:SimpleJava是Java常见问题的集合。中文翻译

    常见问题的集合。中文翻译 ##1。 字符串和数组字符串和数组 字符串是通过引用传递的吗? ##2。 常用方法 比较器与可比较 hashCode() 和 equals() 之间的契约 Java是按引用还是按值传递对象? 迭代与递归 ##3。 类和...

    【IT十八掌徐培成】Java基础第11天-01.Map集合.zip

    Map接口的主要实现类有HashMap、TreeMap、LinkedHashMap、Hashtable等,它们各自有不同的特性和使用场景。 1. HashMap:HashMap是最常用的Map实现,它允许null键和null值。基于哈希表实现,因此具有快速的插入、...

    java核心知识点整理.pdf

    1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM .........................

    JAVA核心知识点整理(有效)

    1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................

    Map地图

    5. Hashtable:线程同步,与HashMap类似,但不支持null键和null值,是遗留类。 在源码分析方面,我们可以关注这些实现类的内部结构,例如HashMap的桶数组、链表和红黑树的转换条件,以及ConcurrentHashMap的分段锁...

    Java Map 集合类简介

    Java的核心类库提供了多种Map实现,如HashMap、TreeMap、LinkedHashMap、Hashtable等。HashMap是默认的无序、非同步实现,适合大多数情况;TreeMap基于红黑树,提供了有序的键值对,但性能略低于HashMap;...

    java的hashtable的用法.pdf

    自Java 5开始,`java.util.Map`接口和它的实现如`HashMap`、`TreeMap`提供了更灵活和高效的选择。特别是`ConcurrentHashMap`,它在多线程环境中提供了高性能的并发访问。 9. **非序性**: 和`HashMap`一样,`...

    Hashtable的使用

    - **线程安全**:`Hashtable`是线程安全的,这意味着在多线程环境下,它的操作不会引发数据不一致问题。而`HashMap`则不是线程安全的,如果需要在多线程环境下使用,通常需要使用`Collections.synchronizedMap()`来...

    java map实例,排序

    本篇文章将详细探讨`HashMap`, `LinkedHashMap`, `TreeMap`, 和 `Hashtable`这四个常见的Map实现类,特别是它们如何处理排序的问题。 首先,`HashMap`是最常用的Map实现,它不保证元素的顺序,插入顺序和遍历顺序...

    Java集合框架详解

    主要实现类包括HashMap、Hashtable、LinkedHashMap和TreeMap。 1. HashMap:它利用键的hashCode值存储数据,根据键快速定位到值。由于使用了哈希表的存储方式,HashMap通常能够提供较快的读写性能。它的遍历顺序是...

    15.【Map】_map_

    本节将深入探讨`Map`接口及其常见的实现类,包括`HashMap`, `TreeMap`, `LinkedHashMap`等,以及如何使用它们进行数据存储、检索和操作。 一、Map接口概述 `Map`接口在`java.util`包下,它定义了键值对(key-value ...

Global site tag (gtag.js) - Google Analytics