Map接口的用法:

Map接口简介:Map接口是一种双列集合,它的每个元素都包含一个键对象Key和值对象Value,键和值对象之间存在一种对应关系,称为映射。从Map集合中访问元素时,只要指定了Key,就能找到对应的Value。格式如下:

HashMap<K,V>

k:指定的key值,类似于主键值,不能相同;

v:为map的数据值,可以相同,可以重复;

Map 接口的实现类有HashMap、TreeMap、HashTable、Properties等。

HashMap集合与HashTable集合:

  • HashMap集合是Map接口的一个实现类,它用于存储键值映射关系,但必须保证不出现重复的键。它是线程不安全的,但是效率高;可以存储null的key值和value值。而且HashMap添加的数据是按照数据的HashCode来进行排序的,并不是按照添加顺序进行排序的。其底层为:数组+链表+红黑树
    HashMap的常用方法:
Map m = new HashMap();
        m.put("AA",111);
        m.put("BB",222);
        m.put("CC",333);
        m.put("CC",321);
        System.out.println(m);
        System.out.println("equals:--->" + m.equals("AA"));
        System.out.println("isEmpty:--->" + m.isEmpty());
        System.out.println("keySet:--->" + m.keySet());
        System.out.println("values:--->" + m.values());
        System.out.println("size:--->" + m.size());
        System.out.println("containsKey:--->" + m.containsKey("AA"));
        System.out.println("containsValue:--->" + m.containsValue(000));
        System.out.println("get:--->" + m.get("BB"));
        System.out.println("getOrDefault:--->" + m.getOrDefault("BB",""));
        System.out.println("keySet:--->" + m.keySet());         //返回所有key构成的set集合      可用Iterator遍历
		System.out.println("entrySet:--->" + m.entrySet());     //返回所有key-value构成的set集合
  • HashMap里面还有一个实现类:LinkedHashMap集合,该集合为双链表结构,添加了一堆指针,指向前后的元素,且必须保证不出现重复的键。所以LinkedHashMap添加的数据会根据输入的顺序进行排序。对于频繁使用插入修改删除的集合,使用该集合效率会更高。
LinkedHashMap map = new LinkedHashMap();
        map.put(1,"abc");
        map.put(2,"ac");
        map.put(4,"aa");
        map.put(3,"ab");

        Set set =  map.entrySet();						//Map的遍历,将Map转换成Set
        Iterator iterator = set.iterator();				//调用Iterator迭代器
        while (iterator.hasNext()) {
            System.out.println(iterator.next());		//会按照添加数据的顺序输出 1 2 4 3
        }

注意:HashMap集合中没有Iterator这个迭代器,如果需要遍历的话,则需要把Map转换成Set集合,再去调用Iterator迭代器进行遍历输出。

  • Map接口中还有一个实现类Hashtable,它和HashMap十分相似,区别在于Hashtable是线程安全的,效率低。且HashMap是不能存储null的key值和value值的。但Hashtable类有一个子类Properties在实际应用中非常重要。
  • Properties主要用来存储字符串类型的键和值,在实际开发中,经常使用Properties集合来存取应用的配置项。
//常用来处理配置文件,key和value都是String类型
		Properties p = new Properties();
        FileInputStream f = new FileInputStream("test.properties");
        p.load(f);      //加载流对应的文件
        String name = p.getProperty("name");
        String age = p.getProperty("age");

        System.out.println(name + "--"  + age);

TreeMap集合:

TreeMap能够保证按照添加到集合里面的key-value类型进行排序(必须为同一类型),实现排序遍历。此时,我们就可以考虑key的使用自然排序或定制排序(通过Comparator对比函数进行自定义排序方法),TreeMap的底层其实是使用了红黑树。

Comparator co = new Comparator() {					//自定义co排序方法
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof User && o2 instanceof  User) {
                    User user1 = (User)o1;
                    User user2 = (User)o2;
                    return Integer.compare(user1.getAge(),user2.getAge());	按照age元素进行排序
                }
                throw new RuntimeException("输入数据不匹配");
            }
        };

        TreeMap map = new TreeMap(co);					//TreeMap传入自定义排序方法co
        map.put(new User("VX1",1),6);
        map.put(new User("VX2",4),5);
        map.put(new User("VX5",6),4);
        map.put(new User("VX4",3),3);
        map.put(new User("VX5",6),2);
        map.put(new User("VX5",7),1);
        Set set = map.entrySet();					//map转set进行遍历
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

关于Map集合的详解:

Map中的Entry:不可重复,无序的;可以使用Set存储所有entry,可利用Set调用Iterator迭代器进行遍历;

Map中的key:不可重复,无序的;相当于使用Set存储所有key;如果是自定义类,key所在的类就必须要重写equals()和hashCode()方法

Map中的value:可重复的,无序的;相当于使用Colleaction存储所有value;如果是自定义类,value所在的类就必须要重写equals()

图:

HashMap的底层实现原理:(基于jdk8)

HashMap map = new HashMap();

  • 在实例化HashMap集合后,底层会自动创建一个没有明确长度的数组Node[] table;
    Map.put(key,value)---->
    当对map进行第一次put()添加数据时,会生成对数组Entry[] table赋予长度16.
  • 对于HashMap添加元素。首先,调用key所在类的hashCode()计算key的哈希值,经过算法计算后,得到的Entry数组的某个确定位置
  • 如果此位置上数据为空,则添加成功;
  • 如果此位置上数据不为空,则意味着有一个或多个数据(以链表形式存在),此时需要比较key值和已经存在的数据的哈希值:
  • 如果key的哈希值相同,则元素不重复,添加成功;
  • 如果key的哈希值位不相同,则元素重复,添加不成功;继续比较,需要再调用equals()方法进行比较;
  • 如果equals()返回false,则添加成功;
  • 如果equals()返回true,则添加不成功;使用后添加进去的value的值代替原value的值。(value2代替value1这是跟HashSet最大区别)。

注意:在HashMap的底层中,如果多个数据存储在同个位置,会以链表的方式进行存储。而且当内部长度不够时,会自动扩容,扩容为 原来的2倍,再将原有的数据复制过来。

jdk7与jdk8中HashMap的底层实现原理的区别:(jdk7)

  • new HashMap() 时会自动创建一个长度为16的数组;
  • jdk8底层的数组是:Node[] , 而jdk7底层的数组是:Entry[] ;
  • 再进行put()之前就已经赋予长度为16的数组;
  • jdk7的底层:数组+链表;
  • jdk8的底层:数组+链表+红黑树 ;当数组的某一个位置上的元素以链表形式存在的数据个数 > 8 ,且当前数组的长度 > 64 ;
    此时索引位置上的所有数据都将改为红黑树进行存储(红黑树:左边小,右边大);