引言
前两篇博文 Java 集合体系详解——List体系有序集合和 Java 集合体系详解——Set体系无序不重复集合总结了下List和Set体系集合的用法,这一篇主要总结下一个新的体系Map
一Map体系的访问方式
Map的访问也和HashSet的特点一样是无需的,Map体系与Set体系不同并不实现Iterator接口,当然也不会具有迭代器,那么Map集合怎么访问呢?间接通过Set的迭代器,Map集合访问方式主要有两种:keySet和entrySet
- keySet:将Map中所有的键存入到Set集合,再借助Set的迭代器Iterator取出所有的键,最后再根据get方法获取到键对应的值。
Map<T,T> map=new HasMap<T,T>()
Set<T> set=map.keySet();//得到Set集合
Iterator<T> it=set.iterator();//得到Set集合的迭代器
while(it.hasNext()){
String key=it.next();//通过迭代器获取键
String value=map.get(key);//map根据键获取对应的值
}
- entrySet:将Map集合的映射关系Map.Entry存入到Set集合中,映射关系的数据类型就是Map.Entry。
/*
Map.Entry:其实Entry是Map接口中的一个内部接口(因为能加static修饰符只能是成员变量,所以只能是成员接口),因为只能先有Map集合才有映射关系,而映射关系是直接处理成员数据的,所以设计为内部接口。
interface Map{
public static interface Entry{
public abstract Object getKey();
...
}
}
//嵌套接口的实现
class HashMaps implements Map{
class Maps implements Map.Entry{
public Object getKey();
...
}
}*/
Set<Map.Entry<T,T>> entrySet=map.entrySet();//得到Set集合
Iterator<Map.Entry<T,T>> it=entrySet.iterator();//得到Set集合的迭代器
while(it.hasNext()){
Map.Entry<T,T> m=it.next();//通过迭代器获取映射关系
String key=m.getKey();//通过映射关系获取key
String value=map.getValue(key);
}
二Map体系集合之HashTable(已基本被HasMap替代)
哈希表HashTable实现了Map接口,该哈希表将键映射到对应的值,该集合是线程同步的。任何非null对象都可以作为键Key或者值Value,换言之不允许存入null键null值。为了能成功在哈希表中存储和获取对象,用作键的对象必须实现hashCode和equals方法。
三Map体系集合之HashMap
HashMap底层数据结构也是哈希表,除了非同步和允许使用null键和null值、效率比较高以外,其他功能和HashTable类相同。
要保存到Map集合的对象完成三步工作:实现Comparable<对象>、覆写compareTo、hashCode、equals方法,至于原因吗,因为哈希体系。
class Person implements Comparable<Person>{
private String name;
private int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
public int compareTo(Person s){
int num=new Integer(this.age).compareTo(new Integer(s.age));
if(num==0){
return this.name.compareTo(s.name);
}
else{
return num;
}
}
//为了去除重复必须重新构造hashCOde
public int hashCode()
{
return name.hasCode()+age*37;
}
//当哈希值相同的时候才会执行
public boolean equals(Object obj){
if(!(obj instanceof Person)){
throw new ClassCastException("类型不匹配");
}
Person p=(Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
public String toString(){
return "姓名:"+name+"年龄:"+age;
}
}
//把Person对象保存到HasMap中,以Person对象为键,对应的籍贯为值,姓名和年龄相同就认为是相同的人,需要保持唯一性
public static void main(String[] args){
Map<Person,String> map=new HashMap<Person,String>();
map.put(new Person("zhang3",18),"beijing");
map.put(new Person("zhang4",19),"didu");
map.put(new Person("zhang5",21),"modu");
//map.put(new Person("zhang5",21),"将要替换掉modu");若已经保存了(new Person("zhang5",21),"modu");再put(new Person("zhang5",21),"将要替换掉modu"),由于已经保存了(new Person("zhang5",21))再put时会替换原来的值变成新的值
//第一种keySet方式遍历
Set<Person> set=map.keySet();
Iterator<Person> it=set.iterator();//得到Set集合的迭代器
while(it.hasNext()){
Person key=it.next();//通过迭代器获取键
String value=map.get(key);//map根据键获取对应的值
System.out.println(key.toString()+":"+value);
}
//第二种方式entrySet
Set<Map.Entry<Person,String>> entrySet=map.entrySet();
Iterator<Map.Entry<Person,String>> iter=entrySet.iterator();//得到Set集合的迭代器
while(iter.hasNext()){
Map.Entry<Person,String> pa=iter.next();//通过迭代器获取键
Person key=pa.getKey();//获取键
String value=pa.getValue();
System.out.println(key.toString()+":"+value);
}
}
四Map体系集合之TreeMap
TreeMap是可以排序的Map集合,TreeMap底层数据结构是二叉树,线程不同步,可以用于给Map中的键Key排序,可以通过compareTo方法来排序,也可以通过传入比较器构造Map集合来覆盖掉comareTo方法来实现排序。
1例:把Person对象保存到TreeMap,并按照姓名、年龄排序
class Person implements Comparable<Person>{
private String name;
private int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
//默认的是先根据年龄排序的,年龄相同再按照姓名排序
public int compareTo(Person s){
int num=new Integer(this.age).compareTo(new Integer(s.age));
if(num==0){
return this.name.compareTo(s.name);
}
else{
return num;
}
}
//为了去除重复必须重新构造hashCOde
public int hashCode()
{
return name.hasCode()+age*37;
}
//当哈希值相同的时候才会执行
public boolean equals(Object obj){
if(!(obj instanceof Person)){
throw new ClassCastException("类型不匹配");
}
Person p=(Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
public String toString(){
return "姓名:"+name+"年龄:"+age;
}
}
如果不更改Person对象的源码,就是按照默认的排序规则(先按照年龄再根据姓名),好在TreeMap
class PersonNameComparator implements Comparator<Person>{
public int compare(Person s,Person s2){
int re=s.getName().compareTo(s2.getName());
if(re==0){
return new Integer(s.getAge()).compareTo(new Integer(s2.getAge()));
}
return re;
}
}
测试类
public static void main(String[] args){
TreeMap<Person,String> tm=new TreeMap<Person,String>(new PersonNameComparator());
tm.put(new Person("azhang3",18),"beijing");
tm.put(new Person("dzhang4",19),"didu");
tm.put(new Person("bzhang5",21),"modu");
Set<Map.Entry<Person,String>> entrySet=map.entrySet();
Iterator<Map.Entry<Person,String>> iter=entrySet.iterator();//得到Set集合的迭代器
while(iter.hasNext()){
Map.Entry<Person,String> pa=iter.next();//通过迭代器获取键
Person key=pa.getKey();//获取键
String value=pa.getValue();
System.out.println(key.toString()+":"+value);
}
}
2 获取指定字符串中的字母次数,如“asdfsafddwewdwss”,打印结果a(1)d(4)……
public String charCount(String str){
chars[] chs=str.toCharArray();
TreeMap<Character,Integer> tm=new TreeMap<Character,Integer>();//错误的,泛型不允许使用基本类型必须使用引用类型TreeMap<char,int> tm=new TreeMap<char,int>();
int count=0;
for(int x=0;x<chs.length;x++){
if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z')){
continue;
}
Integer value=tm.get(chs[x]);
if(value!=null){
count=value;
}
count++;
tm.put(chs[x],count);
count=0;
}
StringBuilder sb=new StringBuilder();
Set<Map.Entry<Character,Integer>> enteySet=tm.entrySet();
Iterator<Map.Entry<Character,Integer>> it=enteySet.iterator();
while(it.hasNext()){
Map.Entry<Character,Integer> me=it.next();
Character ch=me.getKey();
Integer value=me.getValue();
sb.append(ch+"("+value+")");
}
return sb.toString();
}