已实现的子类:
1、HashMap
底层数据结构是哈希表,可以存放null键和null值,该集合是线程不同步的,效率高,jdk1.2出现。
2、HashTable
底层数据结构是哈希表,不可以存放null键和null值,该集合是线程同步的,效率低,jdk1.0出现。
3、TreeMap
底层是二叉树数据结构,线程不同步,可以用于给Map中的键进行排序。
Map中取元素的方式:
1、Map中的取出方式
(1)Map.Entry:这是一种描述键值对之间的映射关系的一种特殊数据类型,可以指定泛型,而Entry接口是Map接口的一个静态子接口,又称为映射项,意指在Map存在后用来表示Map中键值的关系,而Map.Entry接口通常被一个内部类实现。。。。。通过map的entrySet方法来获取Map.Entry类型的Set集合,然后通过Set迭代器来获取Map.Entry对象,用这个对象调用其内部的getKey和getValue方法获取建和值。
(2)通过keySet方法获得一个存取key的Set集合,然后通过map的getKey方法获取这些键,通过map的get(key)方法获取对应的值。
下面用一个例子来实现这两种方法
exp1:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name,int age) {
// TODO 自动生成的构造函数存根
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
// TODO 自动生成的方法存根
return super.toString();
}
//重写compareTo方法自定义排序规则
@Override
public int compareTo(Student s) {
// TODO 自动生成的方法存根
int num = new Integer(this.getAge()).compareTo(new Integer(s.getAge()));
System.out.println(this.name+"-compareTo-"+s.getName());
if(num == 0)
return this.getName().compareTo(s.getName());
return num;
}
//重写hashCode方法
@Override
public int hashCode(){
// TODO 自动生成的方法存根
return name.hashCode()+age*32;
}
//重写equals方法自定义元素唯一性标准
@Override
public boolean equals(Object obj) {
// TODO 自动生成的方法存根
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student) obj;
return this.name.equals(s.name)&&this.age == s.age;
}
}
public class MapTest1 {
public static void main(String[] args) {
Map<Student,String> map = new HashMap<Student,String>();
map.put(new Student("张三", 18), "上海");
map.put(new Student("李四", 19), "西安");
map.put(new Student("王五", 20), "火星");
/*
//第一种取出方式
Set<Student> keySet = map.keySet();
Iterator<Student> it = keySet.iterator();
while(it.hasNext()){
Student s = it.next();//key
String attr = map.get(s);
System.out.println(s.getName()+"-"+s.getAge()+":"+attr);
}
*/
//第二种取出方式
Set<Map.Entry<Student, String>> set = map.entrySet();
for(Iterator<Map.Entry<Student, String>> it = set.iterator();it.hasNext();)
{
Map.Entry<Student, String> entry = it.next();
Student s = entry.getKey();
String attr = entry.getValue();
System.out.println(s.getName()+"-"+s.getAge()+":"+attr);
}
}
}
看完这两种方法后再看一下这个例子中重写了equals和hashCode方法,当要指定元素唯一性时可能要涉及多个方面,而equals方法本身比较的是某个对象的一项内容,比如Integer和String对象,因此需要重写。然后重写hashCode方法保证元素唯一性主要是以实例为主,而不是对象本身,比如两个不同的对象拥有不同的哈希码直接存入,但此时实例却相同,从而省略了equals方法判断这一步,导致与实际情况不符。
但为什么要重写compareTo方法呢?因为当有多个对象要被存储时,此时存储的容器就有了多种选择,可以是哈希表、二叉树、数组等等,如果将多个对象存入了二叉树中,元素就必须被赋予排序规则,否则会抛出异常,所以为了保险起见需要定义比较器,通过实现Comparable或Comparator接口均可。
由于Map本身也是一个对象,而对象可以作为元素存到集合中,所以Map中也可以嵌套,当然该内部Map对象也可以根据其键值对的含义将其封装为一个类,然后将该类对象存入。下面通过两个例子说明这两种方法。
exp2:
import java.util.HashMap;
import java.util.Iterator;
/*
* Map之间的嵌套
*/
public class MapTest1 {
public static void main(String[] args) {
HashMap<String,HashMap<Integer,String>> school = new HashMap<String,HashMap<Integer,String>>();
HashMap<Integer,String> class1 = new HashMap<>();
HashMap<Integer,String> class2 = new HashMap<>();
school.put("普通班", class1);
school.put("火箭班", class2);
class1.put(1, "张三");
class1.put(2, "李四");
class2.put(1, "王五");
class2.put(2, "赵六");
Iterator<String> it1 = school.keySet().iterator();
while(it1.hasNext()){
String cla = it1.next();//取班级的key
HashMap<Integer, String> claMap = school.get(cla);//取班级的值
System.out.println(cla);
Iterator<Integer> it2 = claMap.keySet().iterator();
while(it2.hasNext()){
int num = it2.next();
String name = claMap.get(num);
System.out.println(num+"::"+name);
}
}
}
}
exp3:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/*
* Map存入对象
*
*/
public class MapTest2 {
public static void main(String[] args) {
HashMap<String, List<Student>> school = new HashMap<String,List<Student>>();
List<Student> rClass = new ArrayList<Student>();
List<Student> nClass = new ArrayList<Student>();
school.put("普通班", nClass);
school.put("火箭班", rClass);
nClass.add(new Student(1,"王五"));
nClass.add(new Student(2,"赵六"));
rClass.add(new Student(1,"张三"));
rClass.add(new Student(2,"李四"));
Iterator<String> it = school.keySet().iterator();
while(it.hasNext()){
String className = it.next();
List<Student> list = school.get(className);
System.out.println(className);
for(Student item : list){
System.out.println(item.getNum()+"::"+item.getName());
}
}
}
}
class Student{
private String name;
private int num;
public Student(int num,String name) {
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public int getNum() {
return num;
}
}
对于TreeMap,如果存入对象并没有自然顺序或要按照给定顺序排序,必须要定义一个比较器来使元素有自然顺序,下面通过一个例子说明。
exp4:
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/*
*
* 输入一个字符串,打印每个字符以及出现的次数并使字符倒序排序
* 输出格式为:字符(次数)字符(次数)...
*
* 思路:(1)将字符串中的字符存到一个数组中,然后对数组遍历,如果当前元素在TreeMap中不存在
* 那么添加进去,并将该元素和其出现次数作为一对键值对;如果当前元素已存在,定义一个
* 累加器,在已存在次数基础上自加一次再存入TreeMap中,由于key值相同,所以以前的
* 记录将会被更新,第一种情况也是如此,只不过累加器是从零开始的。最后按照给定格式取出
* 存在Map中的元素。
* (2)创建比较器自定义比较规则
*/
public class TreeMapTest {
public static String charCount(String str){
char[] ch = str.toCharArray();
TreeMap<Character, Integer> treeMap = new TreeMap<>(new Compare());
int count = 0;
for(int i=0;i<ch.length;i++){
if(!(ch[i]>='a'&&ch[i]<='z'||ch[i]>='A'&&ch[i]<='Z'))
continue;
Integer value = treeMap.get(ch[i]);
if(value!=null)
count=value;
count++;
treeMap.put(ch[i], count);
count=0;
}
//System.out.println(treeMap);
StringBuffer sb = new StringBuffer();
Set<Map.Entry<Character, Integer>> set = treeMap.entrySet();
Iterator<Map.Entry<Character, Integer>> it = set.iterator();
while(it.hasNext()){
Map.Entry<Character, Integer> entry = it.next();
sb.append(entry.getKey()+"("+entry.getValue()+")");
}
return sb.toString();
}
public static void main(String[] args) {
String str = charCount("aababcabcd");
System.out.println(str);
}
}
//定义一个比较器,使字符按照原有顺序的倒序排列
class Compare implements Comparator<Object>{
@Override
public int compare(Object obj1,Object obj2) {
// TODO 自动生成的方法存根
if(!(obj1 instanceof Character)||(obj2 instanceof Character))
{
Character ch1 = (Character) obj1;
Character ch2 = (Character) obj2;
int result = ch1.compareTo(ch2);
if(result>0)
return -1;
else if(result<0)
return 1;
return 0;
}
throw new RuntimeException("类型不匹配");
}
}