什么是 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工作的主要原理:散列
要了解什么是哈希图及其工作原理,让我们先谈谈哈希和哈希函数。哈希函数只是数学意义上的函数。所以有一些输入值(一个对象,一段数据)并且函数使用适当的规则将其转换为输出值 - 哈希。哈希通常是适当长度的十六进制数。转换过程的规则可能不同,但都遵循以下原则:
- 特定的输入(对象)具有特定的哈希码。
- 如果两个对象相等,则它们的哈希码也相等。反之则不然。
- 如果哈希码不同,则对象肯定不相等。
- 有时不同的对象可以有相同的散列码。这是一个不太可能发生的事件,称为“碰撞”,高质量的哈希函数应该将碰撞的可能性降到最低。
在 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 课程中的视频课程
GO TO FULL VERSION