05集合-----02map

1、map接口常用的方法

public static void main(String[] args) {
    /*
    * java.util.Map接口中常用的方法
    * 1、Map和Collection没有继承关系
    * 2、Map以key和value的方式存储数据:键值对
    *   key和value都是引用数据类型
    *   key和value都是存储的对象的存储地址
    *   key起到主导地位,value是key的一个附属品
    * 3、Map接口的常用方法
    *   V map(K key,V value)  向map集合中添加键值对
    *   V get(Object key)    通过key获取value
    *   void clear()      清空map集合
    *   Boolean containsKey(Object key)  判断Map中是否包含某个key
    *   contains 底层比较都是equal方法,自定义的类都需要重写equal方法
    *   Boolean containsValue(Object value)  判断Map中是否包含某个value
    *   boolean isEmpty()   判断集合中元素个数是否为0
    *   Set<K>  keySet()    获取Map集合中所有的key
    *   V remove(Object key)  通过指定key删除这个键值对
    *   int  size()   获取集合中键值对的个数
    *   Collection<V> values()   获取集合中所有的value ,返回一个Collection
    *   Set<Map.Entry<K,V>> entrySet() 将集合中的键值对打包返回
    * */
        //创建集合
        Map<Integer,String> map = new HashMap<>();
        //向集合中添加键值对
        map.put(1,"zhangsan");
        map.put(2,"lili");
        map.put(3,"wanghu");

        //通过key获取value
        String  value  = map.get(2);
        System.out.println(value);

        //获取键值对的数量
        System.out.println("键值对的数量"+map.size());

        //删除元素
        map.remove(1);
        System.out.println("键值对的数量"+map.size());

        //判断包含元素
        System.out.println("是否包含元素"+map.containsKey(1));
        System.out.println("是否包含值"+map.containsValue("wanghu"));

        //获取所有value值
        Collection<String> values = map.values();
        //foreach
        for(String s:values){
            System.out.println(s);
        }

        //清空集合
        map.clear();
        System.out.println("键值对的数量"+map.size());

        //判断集合是否为空
        System.out.println(map.isEmpty());


    }

2、遍历map集合

 /*
    * Map集合的遍历
    * */
        Map<Integer,String> map = new HashMap<>();

        //从集合中添加键值对
        map.put(1,"kim");
        map.put(2,"jack");
        map.put(3,"boy");

        //第一种:遍历map集合,获取所有的key,所以的key一个set集合
        Set<Integer> keys = map.keySet();
        Iterator<Integer> it = keys.iterator();
        while(it.hasNext()){
            Integer key = it.next();
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }

        //foreach也可以
        for(Integer key: keys){
            System.out.println(key + "=" + map.get(key));
        }
        System.out.println("----------------------------------------");
        //第二种:Set<Map.Entry<K,V>> entrySet()
        //以上这个方法把Map集合直接全部转换成Set集合
        //Set集合中元素的类型是:Map.Entry
        Set<Map.Entry<Integer,String>> set = map.entrySet();
        //遍历Set集合,每次取出一个Node
        //迭代器
        Iterator<Map.Entry<Integer,String>> it2 = set.iterator();
        while(it2.hasNext()){
            Map.Entry<Integer,String> node = it2.next();
            Integer key = node.getKey();
            String value = node.getValue();
            System.out.println(key + "=" + value);
        }
        System.out.println("****************************************************");
        //foreach  效率更高,获取key和value都是从集合中取,适合大量数据类型
        for(Map.Entry<Integer,String> node:set){
            System.out.println(node.getKey() + "=" + node.getValue());
        }
    }

3、哈希表的数据结构

       /*
        *HashMap集合:
        * 1、HashMap集合底层是哈希表/散列表的数据结构
        * 2、哈希表是一个怎么样的数据结构?
        *   哈希表是一个数组和单向链表的结合体
        *   数组:在查询效率方面较高,随机增删方面效率低
        *   单向链表:在随机增删方面效率高,在查询方面效率低
        *   哈希表将以上的两种数据结构融合在一起,充分发挥他们各自的优点
        * 3、HashMap集合底层的源代码
        *   public class HashMap{
    //HashMap底层实际就是一个数组 (一维数组)
    Node<K,V>[] table;

    //静态内部类 HashMap.Node
    static class Node<K,V>{
        final int hash; //哈希值(哈希值是key的hashCode()方法的执行结果,Hash值通过算法可以转换为数组的下标
        final K key;  //存储到Map集合中key
        final V value; //存储到Map集合中那个value
        Node<K,V> nextl;  //下一个节点的内存地址

    }
}
//哈希表/散列表:一维数组,这个数组中每一个元素是一个单向链表(数组和链表的结合体)
        *4、最主要掌握的:
        * map.put(k,v)
        * v = map.get(k)
        * 以上两个方法的实现原理,是必须掌握的
        * 5、HashMap集合的key特点
        *   无序、不可重复
        *   为什么无序?一维不一定挂到哪个单向链表
        *   不可重复怎么保证的?equals方法
        *   如果key重复了,value要覆盖
        *   放在HashSet集合中的元素也需要同时重写HashCode()和equals方法
        *  注意:同一个单向链表上所有节点的hash值是相同的,因为他们的数组下标是相同的
        *       当时同一个链表上的equals方法返回的false,都不相等
        * 6、HashMap使用不当时,无法发挥性能
        *   假设所有的hashCode()方法返回固定某个值,那么会导致底层哈希表变成纯单向链表,这种情况分为:散列分布不均匀
        *   什么是散列分布均匀?
        *   假设有100个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的,是散列分布均匀的
        *   假设将所有的hashCode()方法返回值设为不一样的值
        *   不行,因为这样的话会导致底层哈希表成为一维数组,没有链表的概念了
        *   散列函数需要重写hashCode()方法
        * 7、重点:放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法
        * 8、HashMap集合的默认初始化容量是16,默认加载因子是0.75
        *   这个默认加载因子是当HashMap集合底层数据的容量达到75%的时候,数组开始扩容
        *   重点:HashMap集合初始化容量必须是2的倍数,这是官方推荐的
        *   这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的
        * */

4、同时重写hashCode和equals方法

 /*
        * 1、
        *  向Map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,再调用equals方法
        *  equals方法有可能调用,也有可能不调用
        *  拿put(k,v)举例,什么时候equals不会调用
        *   k.hashCode()方法返回哈希值
        *   哈希值经过哈希算法转换成数组下标
        *   数组下标位置如果是null,equals方法不会执行
        *  拿get(k,v)举例,什么时候equals不会调用
        *    k.hashCode()方法返回哈希值
        *    哈希值经过哈希算法转换成数组下标
        *    数组下标位置如果是null,equals方法不会执行
        * 2、注意:如果一个类的equals方法重写,那么hashCode方法必须重写
        *   并且equals方法返回如果是true,hashCode()方法返回的值必须一样
        *   equals方法返回的true表示两个对象相同,在同一个单向链表上比较
        *   那么对于同一个单向链表上的节点来说,他们的哈希值都是相同的
        *   所以hashCode()方法的返回值应该相同
        * 3、hashCode方法和equals方法不用研究,直接使用idea工具生成,但是这两个方法需要同时生成
        * 4、终极结论:
        *   放在HashMap集合key,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法
        * 5、jdk中,如果哈希表单向链表中元素超过8个,单向链表会变成红黑树这种结构,当红黑树的节点数量小于8,又会重新把红黑树变成单向链表
        *    这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围,提高效率
        *    初始容量是16,加载因子是0.75
        *
        * */

 

 

       /*
*HashMap集合:
* 1、HashMap集合底层是哈希表/散列表的数据结构
* 2、哈希表是一个怎么样的数据结构?
* 哈希表是一个数组和单向链表的结合体
* 数组:在查询效率方面较高,随机增删方面效率低
* 单向链表:在随机增删方面效率高,在查询方面效率低
* 哈希表将以上的两种数据结构融合在一起,充分发挥他们各自的优点
* 3、HashMap集合底层的源代码
* public class HashMap{
//HashMap底层实际就是一个数组 (一维数组)
Node<K,V>[] table;

//静态内部类 HashMap.Node
static class Node<K,V>{
final int hash; //哈希值(哈希值是key的hashCode()方法的执行结果,Hash值通过算法可以转换为数组的下标
final K key; //存储到Map集合中key
final V value; //存储到Map集合中那个value
Node<K,V> nextl; //下一个节点的内存地址

}
}
//哈希表/散列表:一维数组,这个数组中每一个元素是一个单向链表(数组和链表的结合体)
*4、最主要掌握的:
* map.put(k,v)
* v = map.get(k)
* 以上两个方法的实现原理,是必须掌握的
* 5、HashMap集合的key特点
* 无序、不可重复
* 为什么无序?一维不一定挂到哪个单向链表
* 不可重复怎么保证的?equals方法
* 如果key重复了,value要覆盖
* 放在HashSet集合中的元素也需要同时重写HashCode()和equals方法
* 注意:同一个单向链表上所有节点的hash值是相同的,因为他们的数组下标是相同的
* 当时同一个链表上的equals方法返回的false,都不相等
* 6、HashMap使用不当时,无法发挥性能
* 假设所有的hashCode()方法返回固定某个值,那么会导致底层哈希表变成纯单向链表,这种情况分为:散列分布不均匀
* 什么是散列分布均匀?
* 假设有100个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的,是散列分布均匀的
* 假设将所有的hashCode()方法返回值设为不一样的值
* 不行,因为这样的话会导致底层哈希表成为一维数组,没有链表的概念了
* 散列函数需要重写hashCode()方法
* 7、重点:放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法
* 8、HashMap集合的默认初始化容量是16,默认加载因子是0.75
* 这个默认加载因子是当HashMap集合底层数据的容量达到75%的时候,数组开始扩容
* 重点:HashMap集合初始化容量必须是2的倍数,这是官方推荐的
* 这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的
* */
上一篇:面向对象05


下一篇:Android 极光IM-高级篇-玩聊天app诞生