Java基础之集合框架系列(四)


1.Map概述

1.概述

1.Map也是集合框架中的一员,独立于Collection体系。实际上,Collection称为单列集合,Map称为双列集合

2.Map集合以键值对的方式进行存储,并且需要保持键的唯一性

3.Map包含HashtableHashMapTreeMap三个常见的部分

2.Map接口共性方法

顶级接口 Map<K,V>

顶级接口方法:

1.添加
V put(K key, V value)
向Map集合中添加指定的键值对。
说明:若加入两个键名相同的键值对,则保存后添加的值,先添加的值会被返回

void putAll(Map<? extends K,? extends V> m)
从指定Map中将所有对应关系复制到此Map中。

2.删除
>void clear()
从此映射中移除所有映射关系。
V remove(Object key)
如果存在一个键的映射关系,则将其从此映射中移除。

3.判断
boolean containsKey(Object key)
如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(Object value)
如果此映射将一个或多个键映射到指定值,则返回 true。
boolean isEmpty()
如果此映射未包含键-值映射关系,则返回 true。
boolean equals(Object o)
比较指定的对象与此映射是否相等。

4.获取
V get(Object key)
返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
int size()
返回此映射中的键-值映射关系数。
Collection<V> values()
返回此映射中包含的值的 Collection 视图。
int hashCode()
返回此映射的哈希码值。
>Set<Map.Entry<K,V>> entrySet()
返回此映射中包含的映射关系的 Set 视图。
>Set<K> keySet()
返回此映射中包含的键的 Set 视图。

小提示:所谓视图可以认为是相应集合类的一个实例对象

示例代码:

    //以HashMap为例演示Map的共性方法
    import java.util.HashMap;

    public class MapCommonDemo {

    public static void main(String[] args) {
        //新建HashMap对象,以存储字符串键值对为例
        HashMap<String,String> hm=new HashMap<String,String>();
        //初始化添加字符串键值对元素
        hm.put("key1", "示例元素1");
        hm.put("key2", "示例元素2");
        hm.put("key3", "示例元素3");
        hm.put("key4", "示例元素4");

        //对Map集合进行一次输出
        System.out.println("原始集合:"+hm);

        //根据键获取字符串值
        System.out.println("根据键---key3获取的元素为:"+hm.get("key3"));

        //获取集合的元素数
        System.out.println("该集合所含元素数:"+hm.size());

        //判断集合是否含有指定的键
        System.out.println("判断集合是否存在特定的键---key4:"+hm.containsKey("key4"));      

        //判断集合是否含有指定的值
        System.out.println("判断集合是否存在特定的值---示例元素5:"+hm.containsValue("示例元素5"));  

        //通过指定的键移除映射关系
        hm.remove("key3");
        System.out.println("进行移除操作后的集合:"+hm);

        //对集合中的元素进行清空
        hm.clear();
        System.out.println("判断集合是否为空:"+hm.isEmpty());
    }

}

程序运行结果:

原始集合:{key1=示例元素1, key2=示例元素2, key3=示例元素3, key4=示例元素4}
根据键—key3获取的元素为:示例元素3
该集合所含元素数:4
判断集合是否存在特定的键—key4:true
判断集合是否存在特定的值—示例元素5:false
进行移除操作后的集合:{key1=示例元素1, key2=示例元素2, key4=示例元素4}
判断集合是否为空:true

3.Map子类对象特点

Hashtable:
底层是哈希表数据结构,不可以存入null键和null值。用作键的对象必须实现hashCode()方法和equals()方法。该集合是线程同步的。jdk1.0便存在,效率较低。

HashMap:
底层是哈希表数据结构,允许使用null键和null值。该集合是非线程同步的。jdk1.2后出现,效率较高

TreeMap:
底层是二叉树数据结构。该集合是非线程同步的,可以用于对Map集合中的键进行排序。

说明:Map的结构与Set相似,实际上Set底层使用了Map集合

4.Map集合的元素取出方式

1.Map-keySet

这是Map集合元素的第一种取出方式

相关方法:

Set<K> keySet()
返回此映射中包含的键的 Set 视图。

说明:通过keySet()将Map中的所有键存入到Set集合中,因为Set具备迭代器,所以能以迭代方式取出所有的键。然后再根据Map的get()方法,获取每一个键对应的值。

示例代码:

        //部分代码  
        //新建HashMap对象,以存储字符串键值对为例
        HashMap<String,String> hm=new HashMap<String,String>();
        //初始化添加字符串键值对元素
        hm.put("key1", "示例元素1");
        hm.put("key2", "示例元素2");
        hm.put("key3", "示例元素3");
        hm.put("key4", "示例元素4");

        //利用keySet对Map集合中的元素进行输出
        Set<String> keys = hm.keySet();
        Iterator<String> it = keys.iterator();
        while (it.hasNext()) {
            String key = it.next();          
            System.out.println(key +"--"+hm.get(key));
        }

说明:这也是Map集合和Set集合的联合使用方式

程序运行结果:

key1–示例元素1
key2–示例元素2
key3–示例元素3
key4–示例元素4

2.Map-entrySet

这是Map集合元素的第二种取出方式

相关方法:

Set<Map.Entry<K,V>> entrySet()
返回此映射中包含的映射关系的 Set 视图。

说明:将Map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是Map.Entry

注意:此时迭代器的泛型也应该与返回的Set集合泛型一致,即<Map.Entry<K,V>>

接口 Map.Entry<K,V>

相关方法:

boolean equals(Object o)
比较指定对象与此项的相等性。
K getKey()
返回与此项对应的键。
V getValue()
返回与此项对应的值。
int hashCode()
返回此映射项的哈希码值。
V setValue(V value)
用指定的值替换与此项对应的值。

说明:实际上Map.Entry是Map接口中的一个内部接口

示例代码:

        //部分代码
        //新建HashMap对象,以存储字符串键值对为例
        HashMap<String,String> hm=new HashMap<String,String>();
        //初始化添加字符串键值对元素
        hm.put("key1", "示例元素1");
        hm.put("key2", "示例元素2");
        hm.put("key3", "示例元素3");
        hm.put("key4", "示例元素4");

        //利用entrySet对Map集合中的元素进行输出
        Set<Map.Entry<String,String>> entry=hm.entrySet();
        Iterator<Map.Entry<String,String>> it=entry.iterator();
        while(it.hasNext()){
            Map.Entry<String,String> me=it.next();
            System.out.println(me.getKey()+"---"+me.getValue());
        }

程序运行结果:

key1—示例元素1
key2—示例元素2
key3—示例元素3
key4—示例元素4

5.HashMap

HashMap()
构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity)
构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity, float loadFactor)
构造一个带指定初始容量和加载因子的空 HashMap。
HashMap(Map<? extends K,? extends V> m)
构造一个映射关系与指定 Map 相同的新 HashMap。

特有方法:

Object clone()
返回此 HashMap 实例的浅表副本,并不复制键和值本身。
Set<Map.Entry<K,V>> entrySet()
返回此映射所包含的映射关系的 Set 视图。
Set<K> keySet()
返回此映射中所包含的键的 Set 视图。

6.TreeMap

构造方法:

TreeMap()
使用键的自然顺序构造一个新的、空的树映射。
TreeMap(Comparator<? super K> comparator)
构造一个新的、空的树映射,该映射根据给定比较器进行排序。
TreeMap(Map<? extends K,? extends V> m)
构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序 进行排序。
TreeMap(SortedMap<K,? extends V> m)
构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射。

特有方法:

Object clone()
返回此 TreeMap 实例的浅表副本。

Comparator<? super K> comparator()
返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回 null。


Map.Entry<K,V> firstEntry()
返回一个与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null。
K firstKey()
返回此映射中当前第一个(最低)键。
K lastKey()
返回映射中当前最后一个(最高)键。
Map.Entry<K,V> lastEntry()
返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null。

Map.Entry<K,V> pollFirstEntry()
移除并返回与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null。
Map.Entry<K,V> pollLastEntry()
移除并返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null。


Map.Entry<K,V> ceilingEntry(K key)
返回一个键-值映射关系,它与大于等于给定键的最小键关联;如果不存在这样的键,则返回 null。
K ceilingKey(K key)
返回大于等于给定键的最小键;如果不存在这样的键,则返回 null。
Map.Entry<K,V> floorEntry(K key)
返回一个键-值映射关系,它与小于等于给定键的最大键关联;如果不存在这样的键,则返回 null。
K floorKey(K key)
返回小于等于给定键的最大键;如果不存在这样的键,则返回 null。

Map.Entry<K,V> higherEntry(K key)
返回一个键-值映射关系,它与严格大于给定键的最小键关联;如果不存在这样的键,则返回 null。
K higherKey(K key)
返回严格大于给定键的最小键;如果不存在这样的键,则返回 null。
K lowerKey(K key)
返回严格小于给定键的最大键;如果不存在这样的键,则返回 null。
Map.Entry<K,V> lowerEntry(K key)
返回一个键-值映射关系,它与严格小于给定键的最大键关联;如果不存在这样的键,则返回 null。


NavigableSet<K> descendingKeySet()
返回此映射中所包含键的逆序 NavigableSet 视图。
NavigableMap<K,V> descendingMap()
返回此映射中所包含映射关系的逆序视图。

SortedMap<K,V> headMap(K toKey)
返回此映射的部分视图,其键值严格小于 toKey。
NavigableMap<K,V> headMap(K toKey, boolean inclusive)
返回此映射的部分视图,其键小于(或等于,如果 inclusive 为 true)toKey。

NavigableSet<K> navigableKeySet()
返回此映射中所包含键的 NavigableSet 视图。

NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
返回此映射的部分视图,其键的范围从 fromKey 到 toKey。
SortedMap<K,V> subMap(K fromKey, K toKey)
返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)。

SortedMap<K,V> tailMap(K fromKey)
返回此映射的部分视图,其键大于等于 fromKey。
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
返回此映射的部分视图,其键大于(或等于,如果 inclusive 为 true)fromKey。

7.相关实例应用

1.Map应用

需求描述:

自定义Worker对象,具有年龄和姓名属性,姓名和年龄相同的对象视为同一个Worker对象,以保证元素唯一性。将Worker对象作为键,其家庭住址作为值,存入Map集合

步骤:

1.描述Worker对象,复写hashCode()equals()方法,实现Comparable接口,实现compareTo()方法。
2.定义Map容器,将Worker对象作为键,Worker地址作为值,进行存入。
3.对Map中的元素进行获取操作。

示例代码:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

class Worker implements Comparable{
    private String name;
    private int age;
    //构造方法
    public Worker(String name,int age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    //重写hashCode方法
    public int hashCode() {
        return name.hashCode()+age*39;
    }

    //重写equals方法
    public boolean equals(Object obj) {
        if(!(obj instanceof Worker))
            return false;
        Worker w=(Worker)obj;
        if(!name.equals(w.getName()))
            return false;
        if(age==w.getAge())
            return true;
        return false;
    }

    //实现compareTo方法
    public int compareTo(Object o){
        if(!(o instanceof Worker))
            throw new RuntimeException("类型错误");
        Worker w=(Worker)o;
        int status=name.compareTo(w.getName());
        if(status==0)
            return new Integer(age).compareTo(new Integer(w.getAge()));
        return status;
    }

}

public class WorkerMapDemo {

    public static void main(String[] args) {
        //新建HashMap集合
        HashMap<Worker,String> hm=new HashMap<Worker,String>();
        //向HashMap集合中添加Worker-地址键值对
        hm.put(new Worker("小王",25), "北京");
        hm.put(new Worker("小王",25), "天津");
        hm.put(new Worker("小李",20), "广东");
        hm.put(new Worker("小黄",24), "山西");
        hm.put(new Worker("小曹",22), "山西");

        //利用keySet对HashMap中的元素进行取出
        Set<Worker> sw=hm.keySet();
        Iterator<Worker> it=sw.iterator();
        while(it.hasNext()){
            Worker w=it.next();
            System.out.println(w.getName()+"--"+w.getAge()+"--"+hm.get(w));
        }
    }

}

程序运行结果:

小王–25–天津
小李–20–广东
小黄–24–山西
小曹–22–山西

说明:从程序中可以看出,当向集合中存入键相同的键值对时,后存入的键值对会覆盖先存入的键值对。

相关思想:如果自定义的类可能实例化多个对象,则应该考虑到该类的对象可能会存入Set,List,Map等多种集合结构中,因此需要考虑重写hashCode()equals()方法,以及实现Comparable接口,实现其compareTo()方法

2.TreeMap应用

1.排序

需求描述:

构造Worker对象,按照年龄对Worker对象进行升序排序

说明:
1.由于数据是以键值对形式存在的,所以需要要使用可以排序的Map子类集合对象TreeMap
2.运用比较器Comparator进行自定义排序,类似于TreeSet的处理方式

示例代码:

//省略Worker类代码
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

//自定义比较器类,按照Worker对象的年龄升序排序
class WorkerComparator implements Comparator<Worker>{

    //重写compare方法
    public int compare(Worker w1, Worker w2) {
        if(w1.getAge()>w2.getAge())
            return 1;
        if(w1.getAge()==w2.getAge())
            //当年龄相同时则将姓名作为次要排序条件
            return w1.getName().compareTo(w2.getName());
        else
            return -1;
    }

}

public class TreeMapCompDemo {

    public static void main(String[] args) {
        //实例化自定义比较器对象
        WorkerComparator wc=new WorkerComparator();
        //新建TreeMap集合装载Worker-地址键值对
        TreeMap<Worker,String> tm=new TreeMap<Worker,String>(wc);
        //向TreeMap集合中添加Worker-地址键值对
        tm.put(new Worker("小王", 25), "北京");
        tm.put(new Worker("小李", 20), "广东");
        tm.put(new Worker("小黄", 28), "山西");
        tm.put(new Worker("小曹", 19), "山西");

        //使用entrySet取出元素
        Set<Map.Entry<Worker,String>> entry=tm.entrySet();
        Iterator<Map.Entry<Worker,String>> it=entry.iterator();
        while(it.hasNext()){
            Map.Entry<Worker,String> me=it.next();
            Worker w=me.getKey();
            System.out.println(w.getName()+"--"+w.getAge()+"--"+me.getValue());
        }

    }

}

程序运行结果:

小曹–19–山西
小李–20–广东
小王–25–北京
小黄–28–山西

2.统计

需求描述:

统计字符串中各个字母出现的次数,并按照字母的在字母表中的排列顺序分别对出现次数进行输出

思路:通过需要的结果发现:每一个字母都有对应的次数,说明字母和次数之间都有映射关系,因此可以选择Map集合

步骤:
1.将字符串转换为字符数组,因为要对每一个字母进行操作

2.定义一个Map集合,因为打印结果的字母有顺序,所以用TreeMap集合

3.遍历字符数组,将遍历到的每一个字母作为键查找Map集合中的元素。若返回null,说明Map集合中该字母还不存在,将该字母和1作为键值对存入Map集合中。若返回值不为null,那么获取该键的值并自增后存入

4.将Map集合中的数据按照要求的格式进行输出

示例代码:


import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class StringCountCharDemo {

    //自定义静态方法方法统计字符串中出现的字母次数
    public static void countChar(String s,HashMap<Character,Integer> hm){
        //将字符串转化为字符数组
        char[] c=s.toCharArray();
        //遍历字符数组,并进行计数
        for(int i=0;i<c.length;i++){
            if(!hm.containsKey(c[i]))
                hm.put(c[i], 1);
            else{
                int count=hm.get(c[i]);             
                hm.put(c[i],++count);
            }
        }
    }

    public static void main(String[] args) {
        //目标字符串
        String target="aasdadasfefftyytudada";
        //新建HashMap对象存储字母-频次键值对
        HashMap<Character,Integer> hm=new HashMap<Character,Integer>();

        //统计字母频次
        countChar(target,hm);

        //对HashMap集合中的元素进行取出
        Set<Character> ks=hm.keySet();
        Iterator<Character> it=ks.iterator();
        while(it.hasNext()){
            Character key=it.next();
            System.out.print(key+"("+hm.get(key)+")");
        }
    }

}

程序运行结果:

a(6)s(2)d(4)t(2)e(1)u(1)f(3)y(2)

3.Map拓展

集合的嵌套使用:在Map集合中,还可以将Map集合对象作为值,实现Map的嵌套使用

示例代码:

        //部分代码
        //新建HashMap对象储存高中学生信息
        HashMap<String,Integer> highSchStu=new HashMap<String,Integer>();
        highSchStu.put("bill",16);
        highSchStu.put("tony",15);
        highSchStu.put("marry",18);

        //新建HashMap对象储存大学学生信息
        HashMap<String,Integer> colSchStu=new HashMap<String,Integer>();
        colSchStu.put("tim",20);
        colSchStu.put("park",22);
        colSchStu.put("curry",19);

        //新建HashMap对象储存已经建立的两个HashMap对象
        HashMap<String,HashMap<String,Integer>> schoolStu=
                new HashMap<String,HashMap<String,Integer>>();
        schoolStu.put("高中学生信息:",highSchStu);
        schoolStu.put("大学学生信息:",colSchStu);

        //利用keySet对元素进行取出
        Set<String> keys=schoolStu.keySet();
        Iterator<String> it=keys.iterator();    
        while(it.hasNext()){
            String key=it.next();
            HashMap<String,Integer> hm=schoolStu.get(key);
            //直接将获取到的整个集合输出
            System.out.println(key+hm);
        }

程序运行结果:

高中学生信息:{tony=15, marry=18, bill=16}
大学学生信息:{tim=20, curry=19, park=22}


相关阅读:
菜鸟猿大战Java之集合框架系列(一)
菜鸟猿大战Java之集合框架系列(二)
菜鸟猿大战Java之集合框架系列(三)
菜鸟猿大战Java之集合框架系列(五)

发布了49 篇原创文章 · 获赞 77 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章