集合之Map

已实现的子类:
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("类型不匹配");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值