CodeGym /Java 博客 /随机的 /Java 中的地图接口
John Squirrels
第 41 级
San Francisco

Java 中的地图接口

已在 随机的 群组中发布

什么是 Java 地图接口

Java Map 接口是 Java Collection 框架的一部分,但它不是 Collection 接口的子类型。因此,与列表或其他集合对象相比,它的行为方式不同。Map<Key, Value> 的每个元素代表一个键值对。Key 和 value 都是一些对象。特定映射中的所有键都是唯一的,而值不是,因此它们可以重复。您可能会将 Java 中的 Map 视为一种字典或在线商店目录,您可以在其中使用其唯一索引找到任何项目。键是 Map 中值的唯一标识符。例如,在 Map<String, Item> 中,String 是在线商店中某个 Item 的 ID。 根据文件 Map 有下一个子接口:
    绑定
  • 并发映射<K,V> ;
  • ConcurrentNavigableMap<K,V> ;
  • 逻辑消息上下文
  • 消息上下文
  • 导航地图<K,V> ;
  • SOAP消息上下文
  • 排序映射<K,V>
并实现类:
  • 抽象地图
  • 属性
  • 授权提供者
  • ConcurrentHashMap
  • ConcurrentSkipListMap
  • 枚举图
  • 哈希表
  • 哈希表
  • IdentityHashMap
  • 链表
  • 打印机状态原因
  • 特性
  • 供应商
  • 渲染提示
  • 简单绑定
  • 表格数据支持
  • 树图
  • UI默认值
  • WeakHashMap
  • Java AbstractMap是一个抽象类,它实现了大部分 Map 接口。
  • Java HashMap是一种使用哈希表存储键值对的数据结构。
  • Java TreeMap是一种使用树的数据结构,即用排序的键显示。
  • WeakHashMap使用带有弱键的哈希表,显示的值如果不再使用可以被垃圾收集器删除。
  • LinkedHashMap是一个具有添加元素顺序的映射,允许按插入顺序进行迭代。
  • EnumMap扩展了AbstractMap类以用于枚举键。
  • IdentityHashMap在比较文档时使用引用等价性检查,映射与键比较使用 ==操作而不是 equals()方法
在这里,我们对 Map 接口最流行的实现感兴趣:HashMap、TreeMap 和 LinkedHashMap。顺便说一句,地图元素的顺序取决于具体的实现。比如说,TreeMap 和 LinkedHashMap 具有可预测的元素顺序,而 HashMap 则没有。

映射方法

任何 Map 的主要操作是元素的插入、删除和查找。
  • public Object put(Object key, Object value)将一个元素插入到地图中。
  • public void putAll(Map map)在地图内部插入指定的地图。
  • public Object remove(Object key)根据指定的键删除条目。
  • public Object get(Object key)返回指定键的值。
  • public boolean containsKey(Object key)从此映射中搜索指定的键
  • public Set keySet()返回一个包含所有键的集合视图
  • public Set entrySet()返回一个包含所有键和值的 Set 视图。

什么是哈希表

什么是哈希表?它是 Map<Key,Value> 接口最流行的实现。该数据结构基于散列原理。

HashMap工作的主要原理:散列

要了解什么是哈希图及其工作原理,让我们先谈谈哈希和哈希函数。哈希函数只是数学意义上的函数。所以有一些输入值(一个对象,一段数据)并且函数使用适当的规则将其转换为输出值 - 哈希。哈希通常是适当长度的十六进制数。转换过程的规则可能不同,但都遵循以下原则:
  1. 特定的输入(对象)具有特定的哈希码。
  2. 如果两个对象相等,则它们的哈希码也相等。反之则不然。
  3. 如果哈希码不同,则对象肯定不相等。
  4. 有时不同的对象可以有相同的散列码。这是一个不太可能发生的事件,称为“碰撞”,高质量的哈希函数应该将碰撞的可能性降到最低。
在 Java 中,每个对象都有一个哈希码。它是通过 Object 类的 hashCode 方法计算的,它是所有 Java 对象的父类。通常,开发人员会为他们自己的类重写此方法以及与之关联的 equals方法。

HashMap:它是如何工作的

所以 Class HashMap<K,V> 因为每个 Map 实现都由键和值组成。它使用散列原则存储密钥。HashMap内部键值对存储在“桶”中,这些桶共同构成一个“表”,内部是一个链表数组,初始大小为16. Java 中的 HashMap 使用键的哈希码来确定键/值对应该映射到的桶: HashMap 棘手的特性是表 [] 的每个单元格(桶)不仅保留一对,而且保留几对。它们不存储为显式对象(如 LinkedList),而是存储为隐式链。由于每一对存储到下一对的链接,因此创建了链。也就是说,所有的 HashMap 对都分散在 16 个链上。当您将新对放入表中时,会考虑密钥的哈希值。此哈希不是键对象中内置的哈希码函数。它被认为在0-15的范围内。该对被添加到存储在具有哈希索引的桶中的对链中。这种方法为我们提供了搜索加速。在通过键搜索一对时,无需遍历整个表。考虑密钥的散列,并且仅检查存储在具有散列索引的单元格中的链。如果 HashMap 中的对太多,链就会变得太长。然后数组的大小增加,重新计算所有存储对象的哈希值,并将它们分散在新的链上。

哈希图声明

如果您转到类 HashMap 代码,您会发现下一个声明:

public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
其中K是此映射维护的键类型,V - 映射值的类型。这是在您的代码中使用 Integer 键和 String 值声明 HashMap 的示例:

HashMap<Integer, String> myHashMap = new HashMap<Integer, String>();

哈希映射方法

这是 HashMap 方法的列表。
  • Object get(Object key)返回指定键的值;
  • Object put(Key k, Value v)将键值映射插入到map中;
  • Object remove(Object key)从此映射中删除指定键的映射(如果存在);
  • void clear()从 HashMap 中移除所有键值对;
  • 对象 clone()返回此 HashMap 实例的浅表副本,而不克隆键和值;
  • boolean containsKey(Object key)如果在映射中找到指定的键,则返回 true,否则返回 false;
  • boolean containsValue(Object Value)如果在映射中找到指定的键,则返回 true,否则返回 false;
  • boolean isEmpty()如果地图为空则返回 true,否则返回 false;
  • Set keySet()返回从地图中获取的键的集合;
  • int size()返回键值映射的数量;
  • Collection values()返回地图值的集合;
  • Object remove(Object key)删除指定键的键值对;
  • void putAll(Map m)将地图的所有元素复制到另一个地图。

Java HashMap 示例

让我们用 Java HashMap Example 创建一个程序来演示它是如何工作的:

import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Set;
 
public class HashMap {
 
   public static void main(String[] args) {
 
       {
 
           // HashMap declaration
           HashMap<Integer, String> myHashMap = new HashMap<Integer, String>();
 
           //Adding elements into HashMap
           myHashMap.put(7, "Johnny");
           myHashMap.put(8, "Ivy");
           myHashMap.put(1, "Rick");
           myHashMap.put(4, "Stan");
           myHashMap.put(3, "Kyle");
 
           //print out the map content using Iterator
           Set set = myHashMap.entrySet();
           Iterator iterator = set.iterator();
           while (iterator.hasNext()) {
               Map.Entry mapEntry = (Map.Entry) iterator.next();
               System.out.print("key: " + mapEntry.getKey() + " value: ");
               System.out.println(mapEntry.getValue());
           }
           System.out.println("get an element from myHashMap via key and print the value out:");
           System.out.println(myHashMap.get(8));
           //print out hashMap on standard way:
           System.out.println(myHashMap);
 
           // Get values based on key
           String var = myHashMap.get(2);
           //here we'll get null, we don't have such a key
           System.out.println("Value with key 2: " + var);
           var = myHashMap.get(7);
           System.out.println("Value with key 7: " + var);
 
           // Remove values based on key
           myHashMap.remove(4);
           System.out.println("myHashMap after removing element:");
           System.out.println(myHashMap);
           myHashMap.clear();
           System.out.println("myHashMap after total clearing:");
           System.out.println(myHashMap);
       }
 
   }
}
程序运行结果:

key: 1 value: Rick
key: 3 value: Kyle
key: 4 value: Stan
key: 7 value: Johnny
key: 8 value: Ivy
get an element from myHashMap via key and print the value out:
Ivy
{1=Rick, 3=Kyle, 4=Stan, 7=Johnny, 8=Ivy}
Value with key 2: null
Value with key 7: Johnny
myHashMap after removing element:
{1=Rick, 3=Kyle, 7=Johnny, 8=Ivy}
myHashMap after total clearing:
{}

树图

Java中的TreeMap也实现了Map<Key,Value>接口,但它是基于红黑树数据结构的。树由“节点”和连接节点的线——分支组成。“根”节点在树的顶部。从根开始,可以有分支和节点。它是一个层次结构,你可能会想到这些节点作为根的“孩子”。子节点可以有自己的孩子 - 较低的节点。没有孩子的节点称为“端节点”或“叶”。二叉树是一棵树,其中每个节点都有零,一个, 或两个孩子。二叉搜索树是一种结构,其中每个内部节点存储一个键,有时存储一个关联的值,并且有两个不同的子树(“左”和“右”)。自平衡二叉搜索树是一种基于节点的二叉搜索树,它在面对任意项目插入和删除时自动保持其高度(根以下的最大层数)较小。红黑树是一棵平衡二叉树,具有以下特性:
  • 每个节点要么是红色要么是黑色
  • 根永远是黑色的
  • 每个叶子都是一个 NIL(有点空,空)节点,它是黑色的
  • 如果一个节点是红色的,它的孩子肯定是黑色的。
  • 从节点到后代叶子的每条简单路径都包含相同数量的黑色节点。

一个 TreeMap 特征

TreeMap 使用树数据结构将键存储为节点,并使用红黑树算法对键进行排序。因此,TreeMap 根据其键的自然顺序对其条目进行排序。对于数字自然是升序,对于字符串——字母顺序。如果需要更改排序逻辑,可以使用比较器。以自然的方式对对象进行排序是 TreeMap 的一大优势,以及使用不同的过滤器和条件查找某些对象。

树图方法

  • Object get(Object key)返回对应key的值;
  • Object put(Object key, Object value)将一个映射插入到一个映射中;
  • 如果 TreeMap 包含此键,则Object remove(Object key)删除此键的映射;
  • boolean containsKey(Object key)如果此映射包含指定键的映射,则返回 true;
  • boolean containsValue(Object value)如果 TreeMap 将一个或多个键映射到指定值,则返回 true;
  • Object firstKey()返回排序映射中当前的第一个键;
  • Object lastKey()返回排序映射中当前的最后一个键;
  • void putAll(Map map)将指定地图中的所有映射复制到地图中;
  • Set entrySet()返回映射的集合视图
  • int size()返回键值映射的数量
  • Collection values()返回值的集合视图
  • 对象 clone()返回 TreeMap 的浅表副本
  • void clear()从 TreeMap 中删除所有映射
  • SortedMap headMap(Object key_value)返回地图中小于参数key_value部分的视图
  • Set keySet()返回树图中包含的键的集合视图
  • SortedMap subMap(K fromKey, K toKey)返回此映射部分的视图,其键范围从 fromKey(包含)到 toKey(不包含)
  • Object firstKey()返回 TreeMap 中的第一个键。

树图示例


import java.util.TreeMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
 
public class TreeMapExample {
 
   public static void main(String args[]) {
 
       //TreeMap declaration
       TreeMap<Integer, String> myTreeMap = new TreeMap<Integer, String>();
 
       //put elements to TreeMap
       myTreeMap.put(1, "Stuart");
       myTreeMap.put(23, "Michael");
       myTreeMap.put(7, "Johnny");
       myTreeMap.put(5, "Ivy");
       myTreeMap.put(2, "Alex");
 
       //Display and print out myTreeMap using Iterator
       Set set = myTreeMap.entrySet();
       Iterator iterator = set.iterator();
       while (iterator.hasNext()) {
           Map.Entry myEntry = (Map.Entry) iterator.next();
           System.out.print("key: " + myEntry.getKey() + " value: ");
           System.out.println(myEntry.getValue());
       }
       //TreeMap printed in classical way
       System.out.println(myTreeMap);
       //removing an element with the key =2
       myTreeMap.remove(2);
       //myTreeMap after removing:
       System.out.println(myTreeMap);
   }
}
程序运行结果:

key: 1 value: Stuart
key: 2 value: Alex
key: 5 value: Ivy
key: 7 value: Johnny
key: 23 value: Michael
{1=Stuart, 2=Alex, 5=Ivy, 7=Johnny, 23=Michael}
{1=Stuart, 5=Ivy, 7=Johnny, 23=Michael}

链表

LinkedHashMap 是一种结合了链表和哈希映射的数据结构。的确,LinkedHashMap 扩展了HashMap 类并实现了Map 接口,但是链表是什么呢?LinkedHashMap 的声明:

Map <Integer, String> linkedHashMap = new LinkedHashMap <Integer, String>();
这个新的linkedHashMap继承了HashMap的属性(如table、loadFactor、threshold、size、entrySet),还得到了两个特殊的属性:
  • header 是双向链表的头部。在初始化期间,它指示自己
  • accessOrder 指示如何使用迭代器访问元素。如果为真,则按照上次访问的顺序。如果为 false,访问将按照插入元素的顺序进行。
该链表定义了迭代顺序。通常,它是键插入映射的顺序。

LinkedHashMap 方法

  • Object get(Object key)返回指定键映射到的值,如果此映射不包含键的映射,则返回 null
  • void clear()从地图中删除所有映射。
  • boolean containsKey(Object key)如果指定元素由一个或多个键映射,则返回 true
  • boolean removeEldestEntry(Map.Entry eldest)如果地图从地图中删除其最老的条目,则返回 true
  • Set<Map.Entry<K,V>> entrySet()返回此地图中包含的映射的 Set 视图
  • void forEach(BiConsumer<? super K,? super V> action)对该映射中的每个条目执行给定的操作,直到处理完所有条目或操作引发异常。
  • Object getOrDefault(Object key, V defaultValue)返回指定键映射到的值。如果映射不包含键的映射,则返回 defaultValue。
  • Set<K> keySet()返回映射中包含的键的 Set 视图
  • boolean removeEldestEntry(Map.Entry<K,V> eldest)如果此映射应删除其最旧的条目,则返回 true
  • void replaceAll(BiFunction<? super K,? super V,? extends V> function) 用对该条目调用给定函数的结果替换每个条目值,直到所有条目都已处理或函数抛出异常。
  • Collection<v>values()返回地图中包含的值的集合视图

LinkedHashMap 示例


import java.util.LinkedHashMap;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
   public class HashLinkedListExample {
       public static void main(String args[]) {
           // LinkedHashMap Declaration
           LinkedHashMap<Integer, String> myLinkedHashMap =
                   new LinkedHashMap<Integer, String>();
 
           //Adding elements into LinkedHashMap
           myLinkedHashMap.put(7, "Johnny");
           myLinkedHashMap.put(12, "Rick");
           myLinkedHashMap.put(1, "Kyle");
           myLinkedHashMap.put(5, "Percy");
           myLinkedHashMap.put(85, "Sebastian");
 
           // Generate a Set of entries
           Set set = myLinkedHashMap.entrySet();
 
           // Display and print out the nodes  of LinkedHashMap
           Iterator iterator = set.iterator();
           while(iterator.hasNext()) {
               Map.Entry me = (Map.Entry)iterator.next();
               System.out.print("key: "+ me.getKey() +
                       " value: "+me.getValue()+"\n");
           }
           //print out HashLinkedMap on standard way:
           System.out.println(myLinkedHashMap);
           myLinkedHashMap.put(21, "Ivy");
           System.out.println(myLinkedHashMap);
           myLinkedHashMap.remove(12);
           System.out.println(myLinkedHashMap);
           myLinkedHashMap.put(12, "Ronny");
           System.out.println(myLinkedHashMap);
           myLinkedHashMap.put(1, "Stan");
           System.out.println(myLinkedHashMap);
       }
   }
在这里,我们创建了一个新的 LinkedHashMap,添加了五个元素,然后使用迭代器以经典方式将其打印出来。如您所见,LinkedHashMap 维护插入顺序。之后,我们从 Map 中删除一个元素,然后添加新元素,然后再添加一个带有键的元素,该元素已经在地图上。它替换映射到此键的旧值。 程序运行结果:

key: 7 value: Johnny
key: 12 value: Rick
key: 1 value: Kyle
key: 5 value: Percy
key: 85 value: Sebastian
{7=Johnny, 12=Rick, 1=Kyle, 5=Percy, 85=Sebastian}
{7=Johnny, 12=Rick, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy}
{7=Johnny, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy}
{7=Johnny, 1=Kyle, 5=Percy, 85=Sebastian, 21=Ivy, 12=Ronny}
{7=Johnny, 1=Stan, 5=Percy, 85=Sebastian, 21=Ivy, 12=Ronny}

HashMap、TreeMap、LinkedHashMap比较

HashMap、TreeMap、LinkedHashMap是Map接口的实现。HashMap 和 LinkedHashMap 是哈希键的数据结构。TreeMap 使用其键的自然顺序来组织搜索树。 命令:
  • HashMap 不维护任何顺序。
  • TreeMap 按键的升序对条目进行排序。
  • LinkedHashMap 维护插入顺序。
空键:
  • HashMap 和 LinkedHashMap 允许有一个空键。
  • LinkedHashMap 不允许空键,以防键使用自然顺序或 Comparator 不支持对空键进行比较。
让我们来看一个 Java 地图示例,其中包含本文中讨论的所有三种实现:

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.TreeMap;
 
public class CompMapImpl {
 
 
    public static void main(String[] args) {
        HashMap<Integer, String> hashMap = new HashMap<>();
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<>();
        hashMap.put(5, "Ivy");
        hashMap.put(null, "Joker");
        hashMap.put(1, "First");
        hashMap.put(2, "Kyle");
        hashMap.put(-2, "Paul");
        hashMap.put(3, "Sandy");
 
 
        treeMap.put(5, "Ivy");
        //treeMap.put(null,"Joker");
        treeMap.put(1, "First");
        treeMap.put(2, "Kyle");
        treeMap.put(-2, "Paul");
        treeMap.put(3, "Sandy");
 
        linkedHashMap.put(5, "Ivy");
        linkedHashMap.put(null, "Joker");
        linkedHashMap.put(1, "First");
        linkedHashMap.put(2, "Kyle");
        linkedHashMap.put(-2, "Paul");
        linkedHashMap.put(3, "Sandy");
        System.out.println("HashMap");
        System.out.println(hashMap);
        System.out.println("TreeMap");
        System.out.println(treeMap);
        System.out.println("LinkedHashMap");
        System.out.println(linkedHashMap);
 
 
        LinkedHashMap<String, String> linkedHashMap1= new LinkedHashMap<> ();
        linkedHashMap1.put(null, "Andy");
        System.out.println(linkedHashMap1);
    }
}
下面是运行这个程序的结果:

HashMap
{null=Joker, 1=First, -2=Paul, 2=Kyle, 3=Sandy, 5=Ivy}
TreeMap
{-2=Paul, 1=First, 2=Kyle, 3=Sandy, 5=Ivy}
LinkedHashMap
{5=Ivy, null=Joker, 1=First, 2=Kyle, -2=Paul, 3=Sandy}
{null=Andy}
可以看出,HashMap 中元素的顺序并不明显,treeMap 中靠键,LinkedHashMap 中靠插入顺序。如果我们尝试将空键放入 linkedHashMap,我们将得到 NullPointerException,但在 linkedHashMap1 中,键是 String,我们可以做到。哈希映射是最好的通用映射实现。它提供了最大的搜索速度、快速的存储和检索操作,但您应该记住它的混乱排序。链接的哈希映射继承了 HashMap 的优点并获得了键的顺序。但是,它包含 linkedList,在内存方面相对昂贵。由于维护链表,它在搜索方面比 HashMap 慢,并且在添加/删除方面慢一点。树图存储按升序排序的键。然而, 为了巩固您所学的知识,我们建议您观看我们的 Java 课程中的视频课程
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION