package Map;

import org.junit.Test;

import java.util.Hashtable;
import java.util.Map;

/**
 * 一、Map实现类的结构
 * |---Map:双列数据,存储key-value对的数据     -类似于高中讲得函数:y=f(x)
 *        |---HashMap:作为Map的主要实现类;线程不安全,效率高;可以存储null的key和value
 *                  |---LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序进行遍历
 *                                原因:在原有的HashMap的底层结构上,添加了一对指针,指向前一个和后一个元素
 *                                对于频繁的遍历操作,此类执行效率高于HashMap。
 *        |---TreeMap:保证按照天机的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序
 *                    底层使用红黑树
 *        |---Hashtable:作为古老的实现类;线程安全,效率低;不能存储null的key和value
 *                 |---Properties:常用来处理配置文件。key和value都是String类型
 *
 *          HashMap底层:数组+链表(jdk及之前)
 *                      数组+链表+红黑树(jdk8)
 *  面试题:
 *  1.HashMap的底层实现原理?
 *  2.HashMap和Hashtable的异同?
 *  3.CurrentHashMap与Hashtable的异同?(暂时不讲)
 *
 *  二、Map结构的理解:
 *  Map中的key:无序的、不可重复的,使用Set存储所有的key --->要求key所在的类要重写equals()和hashcode() (以HashMap为例)
 *  Map中的value:无序的、可重复的,使用Collection存储所有的value --->要求value所在类重写equals()
 *  一个键值对:key-value构成了一个Entry对象。
 *  Map中的entry:无序的、不可重复的,使用Set存储所有的entry
 *
 *  三、HashMap的底层实现原理:以jdk7为例说明:
 *          HashMap map=new HashMap();
 *          在实例化以后,底层创建了长度是16的一维数组Entry[] table。
 *          ...可能已经执行过多次put...
 *          map.put(key1,value1);
 *          首先,调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过某种算法计算之后,得到在Entry数组中的存放位置
 *          如果此位置上的数据为空。此时key1-value1添加成功  ---情况1
 *          如果此位置上的数据不为空,(意味着此位置存在着一个或多个数据(以链表形式存在)),比较key1和已经
 *          存在的一个或多个数据的哈希值:
 *                                  如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功  ---情况2
 *                                  如果key1的哈希值与已经存在的某一个数据的哈希值相同,继续比较:调用key1所在类的equals()方法:
                                                                                                                     如果equals()返回false:此时key1-value1添加成功  ---情况3
 *                                                                                                                   如果equals()返回true:使用value1替换相同key的value值
            补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的形式存储

 *          在不断添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空时),则进行扩容。
 *          默认的扩容方式:扩容为原来的2倍,并将原有的数据复制过来。
 *
 *          jdk8相较于jdk7底层实现方面的不同:
 *          1.new HashMap():底层没有创建一个长度为16的数组
 *          2.jdk8底层的数组是Node[],而非Entry[]
 *          3.首次调用put()方法时,底层创建长度为16的数组
 *          4.jdk7底层结构只有:数组+链表 jdk8中的底层结构:数组+链表+红黑树
 *              当数组某一个索引位置上的元素以链表形式存在的数据个数>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
 *
 *          提前扩容是为了尽量让HashMap中的链表少一点,而加载因子的大小就决定着何时开始扩容,加载因子越小,越早开始扩容
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 * @author 
 * @create 2022-04-22-9:27
 */
public class MapTest {
    @Test

    public void test1(){
        Map map=new Hashtable();

        map.put(null,null);
    }
}