Java中的Map

来源:互联网 发布:互联网mysql开发规范 编辑:程序博客网 时间:2024/06/05 20:09

在前面的博文中提到的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否则false2、boolean containsKey(Object key)  判断集合中是否包含指定的key3、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对象同时使用时,比较器的优先级会更高一点!

原创粉丝点击