集合体系2----Map(entry = (key-value))

1. Map接口

  • (1)Map与Collection并列存在。用于保存具有映射关系的数据:key-value。类似于高中的函数:y=f(x)(y→value,x→key)

  • (2)Map结构的理解:

    • ① Map中的key:无序的、不可重复的使用Set存储所有的key 。(key所在的类要重写 equals()和 hashCode()方法。(以HashMap为例))

    • ② Map中的value:无序的、可重复的使用Collection存储所有的value。(value所在的类要重写 equals())。一个键值对:key-value 构成了一个Entry 对象

    • ③ Map中的entry:添加时添加的实际是entry,是entry中有两个属性,一个属性是key,另一个是value

在这里插入图片描述


2. Map 接口的常用实现类

(1)HashMap作为Map的主要实现类;线程不安全的,效率高;存储null 的 key 和 value 。允许使用null键和null值,与HashSet一样,不保证映射的顺序
底层:

  • 数组+链表(jdk 7及之前)
  • 数组+链表+红黑树(jdk 8)

(2)LinkedHashMap保证在遍历map元素时,可以按照添加的顺序实现遍历。原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap。

(3)TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序。底层使用红黑树

(4)Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value。

(5)Properties:常用来处理配置文件。key和value都是String类型。


1. HashMap的底层实现原理

(以 jdk 7为例)

HashMap map=new HashMap();在实例化以后,底层创建了长度为16的一维数组 Entry[ ] table

map.put(key1,value1):把key1,value1放到上述数组中
  • ① 首先,调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置:
  • ② 如果此位置上的数据为空,此时key1-value1添加成功;如果此位置上的数据不为空(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
  • ③ 如果key1的哈希值和已经存在的数据的哈希值都不相同,此时key1-value1添加成功;如果key1和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:
  • ④ 调用key1所在类的equals():如果equals()返回false,此时key1-value1添加成功;如果equals()返回true,使用value1替换value2。

补充:① 添加成功的情况,此时key1-value1和原来的数据以链表的方式存储。② 在不断添加的过程中,会涉及到扩容问题,当超出临界值12(且要存放的位置非空)时扩容,默认的扩容方式:扩容为原来容量的2倍,并将原来的数据复制过来。


2. jdk 8 相较于jdk 7 在底层实现方面的不同:

(1)new HashMap():底层没有创建一个长度为16的数组。

(2)jdk 8 底层的数组是 Node[ ],而非 Entry[ ] 。

(3)首次调用put()方法时,底层创建长度为16的数组。

(4)jdk 7 底层结构只有:数组+链表。
jdk 8 中底层结构:数组+链表+红黑树。当数组的某一个索引位置上的元素以链表形式存在的数据个数>8 且当数组的长度>64时,此时此索引位置上的所有数据改为使用红黑树存储。
在这里插入图片描述
在这里插入图片描述

相关含义
DEFAULT_INITIAL_CAPACITY:HashMap的默认容量,16;
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75;
threshold:扩容的临界值,=容量 × 加载因子:16 * 0.75=12;
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8;
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64

2. TreeMap两种添加方式


import org.junit.Test;

import java.util.*;

/**
 * @author shkstart
 * @create 2019 下午 3:46
 */
public class TreeMapTest {
    
    

    //向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
    //因为要按照key进行排序:自然排序 、定制排序
    //自然排序
    @Test
    public void test1(){
    
    
        TreeMap map = new TreeMap();
        User u1 = new User("Tom",23);
        User u2 = new User("Jerry",32);
        User u3 = new User("Jack",20);
        User u4 = new User("Rose",18);

        map.put(u1,98);
        map.put(u2,89);
        map.put(u3,76);
        map.put(u4,100);

        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
    
    
            Object obj = iterator1.next();
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "---->" + entry.getValue());

        }
    }

    //定制排序
    @Test
    public void test2(){
    
    
        TreeMap map = new TreeMap(new Comparator() {
    
    
            @Override
            public int compare(Object o1, Object o2) {
    
    
                if(o1 instanceof User && o2 instanceof User){
    
    
                    User u1 = (User)o1;
                    User u2 = (User)o2;
                    return Integer.compare(u1.getAge(),u2.getAge());
                }
                throw new RuntimeException("输入的类型不匹配!");
            }
        });
        User u1 = new User("Tom",23);
        User u2 = new User("Jerry",32);
        User u3 = new User("Jack",20);
        User u4 = new User("Rose",18);

        map.put(u1,98);
        map.put(u2,89);
        map.put(u3,76);
        map.put(u4,100);

        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
    
    
            Object obj = iterator1.next();
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "---->" + entry.getValue());

        }
    }


}

3. Properties:常用来处理配置文件

public class PropertiesTest {
    
    

    //Properties:常用来处理配置文件。key和value都是String类型
    public static void main(String[] args)  {
    
    
        FileInputStream fis = null;
        try {
    
    
            Properties pros = new Properties();

            fis = new FileInputStream("jdbc.properties");
            pros.load(fis);//加载流对应的文件

            String name = pros.getProperty("name");
            String password = pros.getProperty("password");

            System.out.println("name = " + name + ", password = " + password);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            if(fis != null){
    
    
                try {
    
    
                    fis.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }

            }
        }

    }
}

猜你喜欢

转载自blog.csdn.net/m0_51755061/article/details/115122729