Java中的Map

在前面的博文中提到的Collection集合是单列集合,但是在现实生活中,也会有双列集合,其中的数据是存在映射关系的,也就是所谓的“键—值”对

Map接口:是双列集合的最顶层接口,其中数据都是以键值对的形式存储的,其中键值是不能重复的,而且每个键值最多映射到一个值,值可以重复。
每次存储都是存储一对元素
—–>HashMap、TreeMap、HashTable
与Collection在集合框架中并列存在

interface Map<K,V>
K - 此映射所维护的键的类型
V - 映射值的类型

Map的通用性方法:

  • 1、添加:

    1、V put(K key, V value)    (可以相同的key值,但是添加的value值会覆盖前面的,返回值是前一个,如果没有就返回null)  (其中的键&值都可以是null)                                        
    2、`putAll(Map<? extends K,? extends V> m)`  从指定映射中将所有映射关系复制到此映射中(可选操作)。
    
  • 2、删除

    1、remove()    删除关联对象,指定key对象
    2、clear()     清空集合对象
    
  • 3、获取

     1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返回的是null。
    
  • 4、判断:

    1、boolean isEmpty()   长度为0返回true否则false
    2、boolean containsKey(Object key)  判断集合中是否包含指定的key
    3、boolean containsValue(Object value)  判断集合中是否包含指定的value
    
  • 4、长度:

    Int size()
    

下面着重说一下Map迭代的方法
1.Set<K> keySet() :返回包含所有键值的Set集合对象,然后通过遍历Set集合获取Map的所有键值
2.Collection<V> values():获取包含所有值的的Collection集合对象,只能获得值,并不能或者键
上述两种方式要么就返回键,要么就返回值,那么我们就会想到有没有一种方式是可以返回键和值呢?
那就是通过定义一个类,其中这个类包含键和值就可以了!

class Entry<K,V>{
    K key;
    V value;
}
ArrayList<Entry> list = new ArrayList<Entry>();
list.add(New Entry("key","value"));

3.Map.Entry对象:那么在Map中确实存在一个内部静态类Entry,其中存储了键和值。其中Entry类使用了自定义泛型。
下面的示例使用了上述三种方式进行了Map的遍历

import java.util.*;

/**
 * Created by Dream on 2017/10/27.
 */
public class MapSee {
    public static void main(String[] args){
        Map<String,String> map = new HashMap<>();
        map.put("Dream","11");
        map.put("Thia","22");
        map.put("Maria","33");
        /*方式一遍历:获得键,然后通过键获得值*/
        Set<String> set = map.keySet();
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            String key = it.next();
            System.out.println("Key:"+key+" Value:"+map.get(key));
        }
        /*方式二遍历:只能获得值*/
        Collection<String> collection = map.values();
        it = collection.iterator();
        while(it.hasNext()){
            System.out.print(it.next()+"   ");
        }
        System.out.println();
        /*方式三:利用Map的静态内部类Entry*/
        Set<Map.Entry<String,String>> list = map.entrySet();
        Iterator<Map.Entry<String,String>> its = list.iterator();
        while(its.hasNext()){
            Map.Entry<String,String> entry = its.next();
            System.out.println("Key:"+entry.getKey()+" Value:"+entry.getValue());
        }
        System.out.println("========直接输出Map=======");
        System.out.println(map);
    }
}

具体实现类:

HashMap:底层的实现原理跟HashSet类似,都是通过哈希表来存储的,HashSet存储的是一个对象,而HashMap存储的是一对数据,不仅存储对象,还存储对象的值!

实现原理:底层是通过哈希表存储的,每次存储一对数据,即“键–值”的时候,首先会调用“键”的hashCode()方法,然后经过一系列运算得到该“键”及其“值”存放的位置,如果该位置上没有数据存放,那么直接将该数据存放在该位置上即可;如果该位置上已经有数据存在,那么会调用“键”的equals方法比较两个“键”是否相同,如果equals返回的是true,那么则视为相同的“键”,此时不再将该“键”所在的数据对添加到该位置上,只是将该“键”所对应的值“覆盖”原先的值,即所谓的“后来者居上”;如果equals返回false,那么该对象允许被存储。至于hashCode方法和equals方法的定义,按需更改!
小示例:

package BasicObject.day17;
import java.util.*;
/**
 * Created by Dream on 2017/10/31.
 */
class Employee{
    String name;
    int age;
    public Employee(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "[name:"+name+", age:"+age+"]";
    }
    public int hashCode(){
        return this.name.hashCode();
    }
    public boolean equals(Object o){
        Employee e = (Employee)o;
        return this.name.equals(e.name) && this.age == e.age;
    }
}
public class hashMapPrac {
    public static void main(String[] args){
        HashMap<Employee,String> employees = new HashMap<>();
        employees.put(new Employee("Sara",21),"1001");
        employees.put(new Employee("Mary",21),"2002");
        employees.put(new Employee("Thia",23),"3003");
        employees.put(new Employee("Tom",25),"4004");
        employees.put(new Employee("Eric",23),"5005");
        employees.put(new Employee("Sara",21),"6666");   //重写了hashCode和equals方法,所以此键值会覆盖Sara第一次出现的键值
        System.out.println(employees);

        /*通过获取键来获取其对应的值
        Set<Employee> set = employees.keySet();
        Iterator<Employee> it = set.iterator();
        while(it.hasNext()){
            Employee e = it.next();
            System.out.print(e+"=="+employees.get(e)+",");
        }*/
        /*仅能获取值
        Collection<String> collection = employees.values();
        Iterator<String> it = collection.iterator();
        while(it.hasNext()){
            System.out.print(it.next()+",");
        }*/
        /*通过entrySet获得全部的键和值*/
        Set<Map.Entry<Employee,String>> set = employees.entrySet();
        Iterator<Map.Entry<Employee,String>> it = set.iterator();
        while(it.hasNext()){
            Map.Entry<Employee,String> entry = it.next();
            System.out.println(entry.getKey()+"=="+entry.getValue());
        }

    }
}

输出结果:
{[name:Tom, age:25]=4004, [name:Eric, age:23]=5005, [name:Sara, age:21]=6666, [name:Thia, age:23]=3003, [name:Mary, age:21]=2002}
[name:Tom, age:25]==4004
[name:Eric, age:23]==5005
[name:Sara, age:21]==6666
[name:Thia, age:23]==3003
[name:Mary, age:21]==2002

TreeMap:跟TreeSet的实现原理类似,也是基于红黑树(二叉树)实现的,会对元素的“键”进行排序存储

实现原理:底层基于红黑树实现,左小有大。既然有排序,那么就需要定义一种比较规则!
1.如果存储的数据的“键”具有自然顺序,那么会按照“键”的自然顺序排序;
2.如果“键”不具备自然顺序,那么“键”所在的类需要实现Comparable接口,把比较规则写在compareTo(Object o)方法上
3.如果“键”不具备自然顺序,而且“键”所在的类也没有实现Comparable接口,那么在创建TreeMap对象的时候,就需要传入一个比较器,将规则定义在compare(Object o1,Object o2)方法内。
存储键—值对时,如果键发生冲突,即存储的键在容器中已经存在,那么后添加的值会覆盖前面所存储的值,简记为后来者居上!

HashTable:与HashMap的方法和底层实现原理是一样的,唯一的不同除了前者在JDK1.0出现,后者在JDK1.2出现,最大的区别在于HashTable是同步的,线程安全的,但是效率低;而HashMap是不同步的,线程非安全的,但是效率高。后者的出现就是为了替代HashTable,因为大部分情况下是不会发生线程安全问题,为了追求效率,大部分情况下使用即使HashMap,即使出现线程非安全问题,我们也可以通过工具类Collections中的方法来实现(具体应用见下一篇博文)

小示例:

package BasicObject.day17;

import java.util.Comparator;
import java.util.TreeMap;

/**
 * Created by Dream on 2017/10/31.
 */
class Person implements Comparable<Person>{
    int id;
    String name;
    public Person(int id,String name){
        this.id = id;
        this.name = name;
    }
    public String toString(){
        return "[id:"+id+","+"name:"+name+"]";
    }

    @Override
    /*返回值:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象*/
    public int compareTo(Person o) {
        /*按照id从小到大排列*/
        return this.id - o.id;
    }
}
class MyComparator implements Comparator<Person>{
    /*随第一个参数小于、等于或大于第二个参数而分别返回负整数、零或正整数*/
    public int compare(Person p1,Person p2){
        /*按照id从大到小排列*/
        return p2.id - p1.id;
    }
}
public class TreeMapPrac {
    public static void main(String[] args){
        /*存储的数据是具有自然顺序的键
        TreeMap map = new TreeMap();
        map.put(1,"1");
        map.put(3,"3");
        map.put(9,"9");
        map.put(2,"2");
        map.put(0,"0");
    输出结果:{0=10, 1=1, 2=2, 3=3, 9=9}
        */
       /*存储的键是不具备自然顺序的*/
       MyComparator comparator = new MyComparator();
        TreeMap<Person,String> map = new TreeMap<>(comparator);
        map.put(new Person(1001,"Dream"),"1001");
        map.put(new Person(4004,"Mary"),"4004");
        map.put(new Person(2002,"Amy"),"2002");
        map.put(new Person(1001,"Thia"),"6666");
        map.put(new Person(3003,"Maria"),"3003");
        System.out.println(map);
    }
}

输出结果:
{[id:4004,name:Mary]=4004, [id:3003,name:Maria]=3003, [id:2002,name:Amy]=2002, [id:1001,name:Dream]=6666}
上述示例中即利用了实现Comparable接口,也实现了自定义的比较器,当对一个TreeMap对象同时使用时,比较器的优先级会更高一点!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值