首页 > 其他分享 >理解Map

理解Map

时间:2023-10-06 13:55:38浏览次数:33  
标签:count Map 返回 value 理解 key new

1.Map

Map用于保存具有映射关系的数据,因此Map集合中保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的valuekeyvalue都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals()方法比较总是返回false

如果把Map里的所有key放在一起来看,它们就组成了一个Set集合(所有的key没有顺序,keykey之间不能重复),实际上,Map确实包含了一个keySet()方法,用于返回Map里所有的key组成的Set集合。

如果把Map里的所有value放在一起看,它们又非常类似于一个List:元素与元素之间可以重复,每个元素可以根据索引来查找,只是Map中的索引不再使用整数值,而是以另一个对象作为索引。如果需要从Map中取出元素,需要提供该元素的key索引。因此,Map有时也被称为字典,或关联数组。

Map接口中定义的常用方法有:

Map接口定义的方法

这里要注意的是V put(K key, V value)方法,该方法用于给Map中添加新的键值对,如果放入重复的key时,新的value会覆盖原有的value;如果新的value覆盖了原有的value,该方法会返回被覆盖的value。当然,如果没有key重复,也就没有覆盖,该方法返回null

测试如下:

public static void main(String[] args) {
    HashMap<String, String> hm = new HashMap<>();
    hm.put("a", "123");
    System.out.println(hm.put("b", "456"));
    System.out.println(hm.put("a", "789"));
}

输出如下:

null
123

第一次输出,并没有覆盖,所以方法返回null;第二次输出,由于Map中已经有了a这个键,所以原有的123被覆盖并返回。

2.HashMap与Hashtable

HashMapHashtable都是Map接口的典型实现类,它们之间的关系完全类似于ArrayListVector的关系:Hashtable是一个古老的Map实现类,它从JDK1.0起就出现了,当它出现时,Java还没有提供Map接口。

HashMapHashtable存在两点典型区别:

  • 1.Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMapHashtable的性能高一点;但如果有多个线程访问同一个Map对象时,使用Hashtable实现类会更好。
  • 2.Hashtable不允许使用null作为keyvalue,但HashMap可以。

为了成功地在HashMapHashtable中存储、获取对象,用作key的对象必须实现hashCode()方法和equals()方法。

HashSet集合不能保证元素顺序一样,HashMapHashtable也不能保证其中的key-value对的顺序。类似于HashSetHashMapHashtable判断两个key相等的标准也是:两个keyhashCode值相等,两个key通过equals()方法比较返回true

除此之外,HashMapHashtable中还包含一个containsValue()方法,用于判断是否包含指定的value。那么HashMapHashtable判断两个value相等的标准是什么呢?这个标准更简单一点:只要两个对象通过equals()方法比较返回true即可。

我们可以做如下测试:

class A {
    private int count;

    public A(int count){
        this.count = count;
    }

    // 根据count的值来判断两个对象是否相等
    public boolean equals(Object obj){
        if(this == obj){
            return true;
        }
        if(obj == null){
            return false;
        }
        if(this.getClass() != obj.getClass()){
            return false;
        }
        A a = (A)obj;
        return this.count == a.count;
    }

    // 根据count来计算hashCode值
    public int hashCode(){
        return this.count;
    }
}

class B{
    @Override
    public boolean equals(Object obj) {
        return true;
    }
}

public class HashtableTest {

    public static void main(String[] args) {
        Hashtable ht = new Hashtable<>();
        ht.put(new A(1000),"Java");
        ht.put(new A(2000),"Python");
        ht.put(new A(3000),new B());

        //由于Hashtable中有一个B对象,它与任何对象通过equals()方法比较都返回true
        // 所以这里不管测试的字符串是什么,它都会返回true
        System.out.println(ht.containsValue("123"));

        // 对于key来说,如果两个A对象的hashCode值相等,并且通过equals()方法比较返回true
        // 那么它们就是相等的,就是相同的key
        System.out.println(ht.containsKey(new A(1000)));
    }
}

程序输出:

true
true

1.因为HashMapHashtable保存key的方式与HashSet保存集合元素的方式完全相同,所以HashMapHashtablekey的要求与HashSet对集合元素的要求完全相同。
2.也就是说,当使用自定义类作为HashMapHashtablekey时,如果重写该类的equals(Object obj)hashCode()方法,则应该保证两个方法的判断标准一致:当两个key通过equals()方法比较返回true时,两个keyhashCode()返回值也应该相同。

3.LinkedHashMap

HashSet有一个LinkedHashSet子类,HashMap也有一个LinkedHashMap子类。LinkedHashMap使用双向链表来维护key-value对的次序(其实只需要考虑key的次序),该链表负责维护Map的迭代顺序,迭代顺序与key-value对的插入顺序保持一致。

LinkedHashMap需要维护元素的插入顺序,因此性能略低于HashMap的性能;但因为它以链表来维护内部顺序,所以在使用迭代器访问全部元素时有比较好的性能。

public class LinkedHashMapTest {
    public static void main(String[] args) {
        LinkedHashMap<String, Integer> scores = new LinkedHashMap<>();

        scores.put("语文", 90);
        scores.put("数学", 100);
        scores.put("英语", 95);
        // 调用forEach()方法遍历scores里所有的key-value对
        scores.forEach((key,value) -> System.out.println(key + "-->" + value));
    }
}

程序输出:

语文-->90
数学-->100
英语-->95

4.SortedMap接口和TreeMap实现类

正如Set接口派生出SortedSet子接口,SortedSet接口有一个TreeSet实现类一样,Map接口也派生出一个SortedMap子接口,SortedMap接口也有一个TreeMap实现类。

TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。TreeMap也有两种排序方式:

  • 1.自然排序:TreeMap的所有key必须实现Comparable接口,而且所有的key应该是同一个类的对象,否则将会抛出ClassCastException异常。
  • 2.定制排序:创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中的所有key进行排序。采用定制排序不需要Mapkey实现Comparable接口。

类似于TreeSet中判断两个元素相等的标准,TreeMap中判断两个key相等的标准是:两个key通过compareTo()方法返回0。

TreeSet类似的是,TreeMap中也提供了一系列根据key顺序访问key-value对的方法:

方法说明
Map.Entry<K,V> firstEntry() 返回一个与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null
K lastKey() 返回此映射中当前第一个(最低)键,如果映射为空,则返回 null
Map.Entry<K,V> lastEntry() 返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null
K lastKey() 返回此映射中当前最后一个(最高)键,如果映射为空,则返回 null
Map.Entry<K,V> higherEntry(K key) 返回一个键-值映射关系,它与严格大于给定键的最小键关联;如果不存在这样的键,则返回 null
K higherKey(K key) 返回严格大于给定键的最小键;如果不存在这样的键,则返回 null
Map.Entry<K,V> lowerEntry(K key) 返回一个键-值映射关系,它与严格小于给定键的最大键关联;如果不存在这样的键,则返回 null
K lowerKey(K key) 返回严格小于给定键的最大键;如果不存在这样的键,则返回 null
NavigableMap<K,V> subMap(K fromKey,boolean fromInclusive,K toKey,boolean toInclusive) 返回该Map的子Map,其key范围是从fromKey(是否包括取决于第二个参数)到toKey(是否包括取决于第四个参数)
SortedMap<K,V> subMap(K fromKey,K toKey) 返回此Map的子Map,其key范围是从fromKey(包括)到toKey(不包括)
SortedMap<K,V> tailMap(K fromKey) 返回该Map的子Map,其key的范围是大于fromKey(包括)的所有key
NavigableMap<K,V> tailMap(K fromKey,boolean inclusive) 返回该Map的子Map,其key的范围是大于fromKey(是否包括取决于第二个参数)的所有key
SortedMap<K,V> headMap(K toKey) 返回该Map的子Map,其key的范围是小于toKey(不包括)的所有key
NavigableMap<K,V> headMap(K toKey,boolean inclusive) 返回该Map的子Map,其key的范围是小于toKey(是否包括取决于第二个参数)的所有key

针对这些方法做测试如下:

class R implements Comparable{

    int count;

    public R(int count) {
        this.count = count;
    }

    //根据count值判断两个对象是否相等
    @Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(obj == null || this.getClass() != obj.getClass()) return false;
        R r = (R)obj;
        return this.count == r.count;
    }

    // 根据count属性值来判断两个对象的大小
    @Override
    public int compareTo(Object o) {
        R r = (R)o;
        return this.count > r.count ? 1: this.count < r.count ? -1 : 0;
    }

    @Override
    public String toString() {
        return "R [count=" + count + "]";
    }
}

public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap tm = new TreeMap<>();
        tm.put(new R(3),"Java");
        tm.put(new R(-5),"Python");
        tm.put(new R(9),"C++");

        System.out.println(tm);
        // 返回第一个键值对
        System.out.println(tm.firstEntry());
        // 返回最后一个键
        System.out.println(tm.lastKey());
        // 返回比new R(2)大的最小的key-value对
        System.out.println(tm.higherEntry(new R(2)));
        // 返回比new R(2)小的最大key值
        System.out.println(tm.lowerKey(new R(2)));
        // 返回key在new R(-1)和new R(4)之间的子Map
        System.out.println(tm.subMap(new R(-1), new R(4)));
    }
}

程序输出:

{R [count=-5]=Python, R [count=3]=Java, R [count=9]=C++}
R [count=-5]=Python
R [count=9]
R [count=3]=Java
R [count=-5]
{R [count=3]=Java}

标签:count,Map,返回,value,理解,key,new
From: https://www.cnblogs.com/xhengge/p/17744507.html

相关文章

  • 大数据面试题:MapReduce压缩方式
    可回答:1)Hadoop常见的压缩算法有哪些?问过的一些公司:网易云音乐(2022.11),阿里(2020.08)参考答案:1、MapReduce支持的压缩方式压缩格式hadoop自带?算法文件扩展名是否可切分换成压缩格式后,原来的程序是否需要修改DEFLATE是,直接使用DEFLATE.deflate否和文本处理一样,不需要修改Gzip是,直接......
  • 9张图深入剖析ConcurrentHashMap
    前言在日常的开发中,我们经常使用key-value键值对的HashMap,其使用哈希表实现,用空间换取时间,提升查询性能但在多线程的并发场景中,HashMap并不是线程安全的如果想使用线程安全的,可以使用ConcurrentHashMap、HashTable、Collections.synchronizedMap等但由于后面二者使用synchroniz......
  • 9张图深入剖析ConcurrentHashMap
    前言在日常的开发中,我们经常使用key-value键值对的HashMap,其使用哈希表实现,用空间换取时间,提升查询性能但在多线程的并发场景中,HashMap并不是线程安全的如果想使用线程安全的,可以使用ConcurrentHashMap、HashTable、Collections.synchronizedMap等但由于后面二者使用synchroni......
  • UE5 substrate flake normal map 亚克力
    前言本篇将运用UE5的substrate系统制作一个亚克力圆盘效果如下FlakeNormalMap上图中圆盘内的彩色小点是通过噪声函数flake(个人翻译为薄片)normalmap生成的,该函数基于[CellularNoise]https://www.cnblogs.com/chenglixue/p/17742395.html用途:汽车喷漆,及各种细小的......
  • UE5 blend normal map的四种方式
    前言很多情况下玩家靠近物体想看看物体的细节纹理,如果仅仅使用basenormalmaps不会给予玩家好的观感,此时就需要用到detailnormalmaps。也就是说,当玩家靠近物体的,物体的法线将更偏向于detailnormalmaps,更准确地说是detailnormalmaps和normalmap的blend。本篇将介绍blend......
  • HashMap 的实现原理
    (1)简介HashMap基于map接口,元素以键值对方式存储,允许有null值,HashMap是线程不安全的。(2)基本属性初始化大小,默认16,2倍扩容;负载因子0.75;初始化的默认数组;sizethreshold。判断是否需要调整hashmap容量(3)HashMap的存储结构JDK1.7中采用数组+链表的存储形式。HashMap采取Entry数组来......
  • 感性理解梯度下降 GD、随机梯度下降 SGD 和 SVRG
    MLTheory太魔怔了!!!!!从微积分课上我们学到对一个\(\mathscrC^2\)函数,其二阶泰勒展开的皮亚诺余项形式\[f(\bmw')=f(\bmw)+\langle\nablaf(\bmw),\bmw'-\bmw\rangle+o(\|\bmw'-\bmw\|)\]这说明只要\(\bmw'\)和\(\bmw\)挨得足够接近,我们就可......
  • JUC工具类CountDownLatch、CyclicBarrier、Semaphore介绍
    CountDownLatch:它是一种同步工具,用于控制一个或多个线程等待其他线程完成操作后再继续执行。它的作用是让某个线程等待一组操作执行完成,再继续执行自己的任务。CountDownLatch内部有一个计数器,当计数器的值为0时,等待的线程将会被唤醒。通过CountDownLatch的构造函数可以指定计......
  • MapReduce之学习规约
    1、概念2、代码实现自定义一个类:在JobMain(与之前的基本一样)里面:......
  • 管理的本质是控制还是理解?
    管理的本质既不是协调,也不是决策,更不是控制,而是服务,管理通过激活与释放要素对象的能量和潜力,为目标、结果服务。 德鲁克所说“管理是实践,管理是激发善意和潜能”的观点是最贴近实质的,也是最讨巧、智慧的概括,其它的表述要么是部分职能、功能,要是某些手段、方法。为了把管理这......