---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
一、引言
上一篇讲了Collection集合中List和Set接口下ArrayList、Vector、LinkedList和HashSet、TreeSet集合的具体实现、一些用法和注意点。下面我们来说集合框架下另一个体系Map集合下的两个类HashMap和TreeMap的具体实现以及注意点。Collection和Map接口都为集合框架的顶层接口,看上去没有关系,其实其底层的实现还是有关的,粗略的说就是,Map的底层实现就是使用了Set。
下面为Map集合的简单类图
二、Map集合的实现原理与具体应用
我们所要讲的是Map下的3个子类,Hashtable、HaseMap和TreeMap,与Collection类似,只不过Map中存放的是键值对。下面我们来具体的说说这3个类的具体的用法和区别。
1.HashMap
HashMap底层实现的是哈希表数据结构与HasSet类似,HashMap中的元素的相同与否是按照键的值来比较的,也就是说此HashMap集合中不能有相同的键,而键的比较则是跟HashSet集合中类似,先是根据int hashCode();方法来比较进来的键的哈希值,不同则存进来,若是哈希值相同,则使用boolean equals(Object obj);来比较键是否相同,若还是相同,则判定此键在HashMap集合中已存在,则用新的键值对替换旧的键值对,这一点是跟HashSet中不同的。所以若是HashMap中存放自定义的键值对,那么最好对键的类的int hashCode();和boolean equals();方法进行覆写。
Hashtable的用法跟HashMap其实大部分都是相同的,不过Hashtable中不能存放null值null键,而HashMap中则是可以的,Hashtable是线程同步的,效率低,而HashMap是线程不同步的,效率高,其实HashMap就是用来取代Hashtable的,建议用HashMap。
Map集合的取出方式跟Collection集合的取出方式有很大的区别,因为Map集合没有实现Iterable接口,所以Map集合内部也没有定义Iterator类,因而Map集合无法使用迭代器来取值,那么对于Map集合中的键值对我们如何取呢?Java提供了两种方式来对Map集合的取操作。首先是用Set<K> keySet();方法取出Map集合中的所有的键(Key),存放到一个Set集合中,然后对这个Set集合迭代,使用V get(Object key);取出对应的Value值。第二种方式则是用Set<Map.Entry<K, V>>() entrySet();方法取出Map集合中的所有的键值关系,然后将这种关系存放到一个Set集合中,然后对这个Set集合迭代操作,根据Map.Entry中的方法取出对应的键和值。
在上面我们说到了Map.Entry,很多人可能对其很陌生,其实这就是键值对关系的类,Entry其实就是定义在Map接口内部的一个静态接口,如下代码简单示例:
interface Map
{
public static interface Entry
{
public abstract Object getKey();
public abstract Object getValue();
}
}
class HashMap implements Map
{
class Hahs implements Map.Entry//内部接口内部实现,Map.Entry就是一个内部类
{
public Object getValue(){}
public Object getKey(){}
}
}
//Map集合的两种取出方式
import java.util.*;
class KeySetDemo
{
public static void main(String[] args)
{
Map<String, String> map = new HashMap<String, String>();
map.put("001", "zhangsan001");
map.put("002", "zhangsan002");
map.put("003", "zhangsan003");
map.put("004", "zhangsan004");
map.put("005", "zhangsan005");
map.put("003", "zhangsan001111115");//替换"003", "zhangsan003"
//先获取map集合中的所有键的集合
Set<String> keySet = map.keySet();
for(Iterator<String> it = keySet.iterator(); it.hasNext(); )
{
String key = it.next();
String value = map.get(key);
System.out.println(key + " = " + value);
}
System.out.println();
//取出所有的键值关系
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for(Iterator<Map.Entry<String, String>> it = entrySet.iterator(); it.hasNext(); )
{
Map.Entry<String, String> me = it.next();
System.out.println(me.getKey() + "=" + me.getValue() );
}
}
}
2.TreeMap
TreeMap底层实现的也是二叉树的数据结构,存进来的键是有序存放的,是按照元素的自然比较性存放,所以存放到TreeMap中作为键的对象要实现Comparable接口,覆写int compareTo(T obj);方法让元素具备自然比较性,要么就在TreeMap初始化的时候,提供一个自定义的构造器,自定义的构造器要实现Comparator接口,覆写int conpare(T o1, T o2);方法,让容器具备比较性。
/*
需求:按学生对象的年龄进行排序,每个学生对应归属地
因为数据是以键值对形式存放的,
所以要使用可以排序的Map集合,TreeMap
*/
import java.util.*;
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public int hashCode()
{
return name.hashCode() + age * 39;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("不是Student对象");
Student s = (Student)obj;
return this.name == s.getName() && this.age == s.getAge();
}
public String toString()
{
return this.name + ":" + this.age;
}
public int compareTo(Student s)//自然顺序是按照姓名进行排序的
{
if(this.name == s.getName())
return this.age - s.getAge();
return this.name.compareTo(s.getName());
}
}
class TreeMapTest
{
public static void main(String[] args)
{
TreeMap<Student, String> tm = new TreeMap<Student, String>(new MyComparator());
tm.put(new Student("zhangsan001", 23), "北京");
tm.put(new Student("zhangsan002", 24), "天津");//002第一次
tm.put(new Student("zhangsan009", 25), "合肥");
tm.put(new Student("zhangsan003", 25), "海安");//003第一次
tm.put(new Student("zhangsan004", 26), "河南");
tm.put(new Student("zhangsan005", 27), "湖北");
tm.put(new Student("zhangsan006", 28), "安丰");
tm.put(new Student("zhangsan007", 29), "东台");
tm.put(new Student("zhangsan002", 24), "天津");//002第二次
tm.put(new Student("zhangsan003", 25), "合肥");//003第二次
tm.put(new Student("zhangsan003", 25), "连云港");//003第三次
Set<Map.Entry<Student, String>> entrySet = tm.entrySet();
for(Iterator<Map.Entry<Student, String>> it = entrySet.iterator(); it.hasNext(); )
{
Map.Entry me = it.next();
System.out.println(me.getKey().toString() + "=" + me.getValue());
}
}
}
class MyComparator implements Comparator<Student>//自定义构造器是按照年龄进行存放的
{
public int compare(Student s1, Student s2)
{
if(s1.getAge() == s2.getAge())
return s1.getName().compareTo(s2.getName());
return s1.getAge() - s2.getAge();
}
}
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------