article/java/Guava中的类型增强.md
2025-05-16 18:15:38 +08:00

637 lines
24 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Guava中的类型增强
Map - Table、BiMap、Multimap、RangeMap、ClassToInstanceMap
#### 1. 简介[#](https://www.cnblogs.com/cao-lei/p/17806222.html#3979976375)
日常开发中使用Map时经常会遇到很多复杂的处理场景例如多个键的Map、不仅可以根据键获取值也可以根据值获取键且不用遍历、重复键的Map、数字等范围内映射相同的值、内存中缓存对象等Guava提供了以上场景的解决方案。
| 场景 | 解决方案 | 具体实现 |
| ------------------------------------------------ | ------------------ | ------------------------------------------------------------ |
| 多个键的Map | Table | HashBasedTable、TreeBasedTable、ImmutableTable |
| 不仅可以根据键获取值也可以根据值获取键且不用遍历 | BiMap | HashBiMap、ImmutableBiMap |
| 重复键的Map | Multimap | ArrayListMultimap、LinkedListMultimap、LinkedHashMultimap、ImmutableListMultimap、ImmutableSetMultimap |
| 数字等范围内映射相同的值 | RangeMap | TreeRangeMap、ImmutableRangeMap |
| 内存中缓存对象 | ClassToInstanceMap | MutableClassToInstanceMap、ImmutableClassToInstanceMap |
  本博客将详细描述具体的示例代码。
#### 2. 添加依赖[#](https://www.cnblogs.com/cao-lei/p/17806222.html#1443701749)
Maven项目pom.xml中添加依赖
```xml
Copy<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.0.0-jre</version>
</dependency>
```
#### 3. Tbale - 表结构数据[#](https://www.cnblogs.com/cao-lei/p/17806222.html#848306248)
  官方注释翻译:将一对有序键(称为行键和列键)与单个值相关联的集合。
  示例代码(需求: 记录各个公司每个部门的人数):
```swift
Copy// HashMap
Map<String, Integer> deptMap = new HashMap<>();
deptMap.put("A部门", 10);
deptMap.put("B部门", 20);
Map<String, Map<String, Integer>> companyMap = new HashMap<>();
companyMap.put("xx公司", deptMap);
// HashMap 获取值
Integer val = companyMap.get("xx公司").get("A部门");
System.out.println("HashMap 获取值: " + val);
// 创建Hash类型Table, 基于Hash表实现
// Table<R, C, V>中三个泛型: R-行, C-列, V-值
Table<String, String, Integer> hashTable = HashBasedTable.create();
hashTable.put("xx公司", "A部门", 10);
hashTable.put("xx公司", "B部门", 20);
hashTable.put("xx公司", "C部门", 30);
System.out.println("\nHash Table: " + hashTable);
// 创建Tree类型Table, 基于红黑树实现
Table<String, String, Integer> treeTable = TreeBasedTable.create();
treeTable.put("xx公司", "C部门", 30);
treeTable.put("xx公司", "B部门", 20);
treeTable.put("xx公司", "A部门", 10);
System.out.println("\nTree Table: " + treeTable);
// 创建不可变Table, 无法新增、更新或删除
Table<String, String, Integer> immutableTable = ImmutableTable.<String, String, Integer>builder()
.put("xx公司", "C部门", 30)
.put("xx公司", "B部门", 20)
.put("xx公司", "A部门", 10)
.build();
System.out.println("\nImmutable Table: " + immutableTable);
// Table 获取值
Integer val2 = hashTable.get("xx公司", "A部门");
System.out.println("\nTable 获取值: " + val2);
// Table 删除值
Integer remove = hashTable.remove("xx公司", "C部门");
System.out.println("\nTable 删除值: " + remove);
// 根据行获取列和值映射
Map<String, Integer> columnvalueMap = hashTable.row("xx公司");
System.out.println("\nTable 列和值 映射: " + columnvalueMap);
// 根据列获取行和值映射
Map<String, Integer> rowvalueMap = hashTable.column("A部门");
System.out.println("\nTable 行和值 映射: " + rowvalueMap);
// 获取key集合
Set<String> rowKeySet = hashTable.rowKeySet();
System.out.println("\nTable Row key 集合: " + rowKeySet);
Set<String> columnKeySet = hashTable.columnKeySet();
System.out.println("\nTable Column key 集合: " + columnKeySet);
// 获取值集合
Collection<Integer> values = hashTable.values();
System.out.println("\nTable 值集合: " + values);
// 判断包含行
boolean containsRow = hashTable.containsRow("xx公司");
System.out.println("\nTable 包含行: " + containsRow);
// 判断包含列
boolean containsColumn = hashTable.containsColumn("A部门");
System.out.println("\nTable 包含列: " + containsColumn);
// 判断包含行和列
boolean contains = hashTable.contains("xx公司", "A部门");
System.out.println("\nTable 包含行和列: " + contains);
// 判断包含值
boolean containsValue = hashTable.containsValue(10);
System.out.println("\nTable 包含值: " + containsValue);
// 行和列转置 - 行 转 列
Table<String, String, Integer> transposeTable = Tables.transpose(hashTable);
// 获取所有的行
Set<Table.Cell<String, String, Integer>> cells = transposeTable.cellSet();
// 遍历输出
System.out.println("\n遍历输出开始----------------------------");
cells.forEach(cell -> System.out.println(cell.getRowKey() + ", " + cell.getColumnKey() + ", " + cell.getValue()));
System.out.println("\n遍历输出结束----------------------------");
// 转换为嵌套的Map
Map<String, Map<String, Integer>> rowMap = hashTable.rowMap();
System.out.println("\nTable RowMap: " + rowMap);
Map<String, Map<String, Integer>> columnMap = hashTable.columnMap();
System.out.println("\nTable ColumnMap: " + columnMap);
```
  执行结果:
```yaml
CopyHashMap 获取值: 10
Hash Table: {xx公司={A部门=10, B部门=20, C部门=30}}
Tree Table: {xx公司={A部门=10, B部门=20, C部门=30}}
Immutable Table: {xx公司={C部门=30, B部门=20, A部门=10}}
Table 获取值: 10
Table 删除值: 30
Table 列和值 映射: {A部门=10, B部门=20}
Table 行和值 映射: {xx公司=10}
Table Row key 集合: [xx公司]
Table Column key 集合: [A部门, B部门]
Table 值集合: [10, 20]
Table 包含行: true
Table 包含列: true
Table 包含行和列: true
Table 包含值: true
遍历输出开始----------------------------
A部门, xx公司, 10
B部门, xx公司, 20
遍历输出结束----------------------------
Table RowMap: {xx公司={A部门=10, B部门=20}}
Table ColumnMap: {A部门={xx公司=10}, B部门={xx公司=20}}
```
#### 4. BiMap - 双向映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#2347438548)
  官方注释翻译:双映射(或“双向映射”)是一种保留其值及其键的唯一性的映射。此约束使双映射能够支持“反向视图”,即另一个双映射,其中包含与此双映射相同的条目,但具有相反的键和值。
  示例代码(需求: 数组和英文翻译):
```csharp
Copy// 创建BiMap, 底层为两个Hash表的Map
BiMap<Integer, String> biMap = HashBiMap.create();
biMap.put(1, "one");
biMap.put(2, "two");
biMap.put(3, "three");
biMap.put(4, "four");
biMap.put(5, "five");
System.out.println("BiMap: " + biMap);
// 创建不可变BiMap, 无法新增、更新或删除
BiMap<Object, Object> immutableBiMap = ImmutableBiMap.builder()
.put(1, "one")
.put(2, "two")
.put(3, "three")
.put(4, "four")
.put(5, "five")
.build();
System.out.println("\nImmutable BiMap: " + immutableBiMap);
// 通过key获取value
String value = biMap.get(1);
System.out.println("\nBiMap 根据key获取value: " + value);
Integer key = biMap.inverse().get("one");
System.out.println("\nBiMap 根据value获取key: " + key);
// 翻转后修改
biMap.inverse().put("six", 6);
// 返回双映射的逆视图, 并没有创建新对象, 还是之前的对象, 所以操作翻转后的BiMap会影响之前的BiMap
System.out.println("\nBiMap 被影响: " + biMap);
// 底层是HashMap, key不可重复
// value不可重复
try {
biMap.put(11, "one");
} catch (Exception e) {
System.err.println("BiMap 替换value异常: " + e.getMessage());
}
// 翻转后key不能重复
try {
biMap.inverse().put("first", 1);
} catch (Exception e) {
System.err.println("BiMap 替换key异常: " + e.getMessage());
}
// key和value可为null
biMap.put(null, null);
System.out.println("\nBiMap 根据Null key获取Null value: " + biMap.get(null));
System.out.println("\nBiMap 根据Null value获取Null key: " + biMap.inverse().get(null));
// 强制替换key
biMap.forcePut(11, "one");
System.out.println("\nBiMap 获取新key: " + biMap.inverse().get("one"));
// values为Set集合
Set<String> values = biMap.values();
System.out.println("\nBiMap 不重复的value: " + values);
```
  执行结果:
```mipsasm
CopyBiMap: {1=one, 2=two, 3=three, 4=four, 5=five}
Immutable BiMap: {1=one, 2=two, 3=three, 4=four, 5=five}
BiMap 根据key获取value: one
BiMap 根据value获取key: 1
BiMap 被影响: {1=one, 2=two, 3=three, 4=four, 5=five, 6=six}
BiMap 替换value异常: value already present: one
BiMap 替换key异常: key already present: 1
BiMap 根据Null key获取Null value: null
BiMap 根据Null value获取Null key: null
BiMap 获取新key: 11
BiMap 不重复的value: [two, three, four, five, six, null, one]
```
#### 5. Multimap - 多重映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#819077997)
  官方注释翻译将键映射到值的集合,类似于 Map但其中每个键可能与 多个 值相关联。
  示例代码(需求: 学生和各科选修课成绩):
```swift
Copy// 创建Multimap, key为HashMap, value为ArrayList
Multimap<String, Integer> arrayListMultimap = ArrayListMultimap.create();
arrayListMultimap.put("张三", 90);
arrayListMultimap.put("张三", 80);
arrayListMultimap.put("张三", 100);
arrayListMultimap.put("李四", 88);
System.out.println("Multimap key为HashMap, value为ArrayList: " + arrayListMultimap);
// 创建Multimap, key为HashMap, value为HashSet
Multimap<String, Integer> hashMultimap = HashMultimap.create();
hashMultimap.put("张三", 90);
hashMultimap.put("张三", 80);
hashMultimap.put("张三", 100);
hashMultimap.put("李四", 88);
System.out.println("\nMultimap key为HashMap, value为HashSet: " + hashMultimap);
// 创建Multimap, key为LinkedHashMap, value为LinkedList
Multimap<String, Integer> linkedListMultimap = LinkedListMultimap.create();
linkedListMultimap.put("张三", 90);
linkedListMultimap.put("张三", 80);
linkedListMultimap.put("张三", 100);
linkedListMultimap.put("李四", 88);
System.out.println("\nMultimap key为LinkedHashMap, value为LinkedList: " + linkedListMultimap);
// 创建Multimap, key为LinkedHashMap, value为LinkedHashMap
Multimap<String, Integer> linkedHashMultimap = LinkedHashMultimap.create();
linkedHashMultimap.put("张三", 90);
linkedHashMultimap.put("张三", 80);
linkedHashMultimap.put("张三", 100);
linkedHashMultimap.put("李四", 88);
System.out.println("\nMultimap key为LinkedHashMap, value为LinkedHashMap: " + linkedHashMultimap);
// 创建Multimap, key为TreeMap, value为TreeSet
Multimap<String, Integer> treeMultimap = TreeMultimap.create();
treeMultimap.put("张三", 90);
treeMultimap.put("张三", 80);
treeMultimap.put("张三", 100);
treeMultimap.put("李四", 88);
System.out.println("\nMultimap key为TreeMap, value为TreeSet: " + treeMultimap);
// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableList
Multimap<String, Integer> immutableListMultimap = ImmutableListMultimap.<String, Integer>builder()
.put("张三", 90)
.put("张三", 80)
.put("张三", 100)
.put("李四", 88)
.build();
System.out.println("\nMultimap key为ImmutableMap, value为ImmutableList: " + immutableListMultimap);
// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableSet
Multimap<String, Integer> immutableSetMultimap = ImmutableSetMultimap.<String, Integer>builder()
.put("张三", 90)
.put("张三", 80)
.put("张三", 100)
.put("李四", 88)
.build();
System.out.println("\nMultimap key为ImmutableMap, value为ImmutableSet: " + immutableSetMultimap);
// 获取值
Collection<Integer> values = arrayListMultimap.get("张三");
System.out.println("\nMultimap 获取值集合: " + values);
// 获取不存在key的值, 返回的是空集合, 而不是null
Collection<Integer> valuesByNotExistsKey = arrayListMultimap.get("王五");
System.out.println("\nMultimap 获取不存在的Key值集合: " + valuesByNotExistsKey);
// 获取值集合添加值
// 返回的是多重映射中关联的值的视图集合, 并没有创建新对象, 还是之前的对象, 所以操作值集合会影响之前的Multimap
values.add(60);
System.out.println("\nMultimap 被影响: " + arrayListMultimap);
// 获取大小
System.out.println("\nMultimap 大小:" + arrayListMultimap.size());
// 判断是否为空
System.out.println("\nMultimap 是否为空: " + arrayListMultimap.isEmpty());
// 包含key
System.out.println("\nMultimap 包含key: " + arrayListMultimap.containsKey("张三"));
// 包含value
System.out.println("\nMultimap 包含value: " + arrayListMultimap.containsValue(60));
// 包含key-value键值对
System.out.println("\nMultimap 包含key-value对: " + arrayListMultimap.containsEntry("张三", 60));
// 替换value
arrayListMultimap.replaceValues("张三", Arrays.asList(10, 20, 30));
System.out.println("\nMultimap 替换value: " + arrayListMultimap);
// 根据key-value删除
arrayListMultimap.remove("张三", 10);
System.out.println("\nMultimap 根据key-value删除: " + arrayListMultimap);
// 根据key删除
Collection<Integer> removeAll = arrayListMultimap.removeAll("张三");
System.out.println("\nMultimap 根据key删除: " + removeAll);
// 获取key集合
Set<String> keySet = arrayListMultimap.keySet();
System.out.println("\nMultimap 获取key集合(HashSet): " + keySet);
Multiset<String> keys = arrayListMultimap.keys();
System.out.println("\nMultimap 获取key集合(MultiSet): " + keys);
// 获取所有的key-value
Collection<Map.Entry<String, Integer>> entries = arrayListMultimap.entries();
System.out.println("\n遍历key-value开始--------------------------");
entries.forEach(entry -> System.out.println(entry.getKey() + " : " + entry.getValue()));
System.out.println("\n遍历key-value结束--------------------------");
// 转换为Map<K, Collection<V>>
Map<String, Collection<Integer>> collectionMap = arrayListMultimap.asMap();
System.out.println("\nMultimap 转换为Map<K, Collection<V>>: " + collectionMap);
```
  执行结果:
```mipsasm
CopyMultimap key为HashMap, value为ArrayList: {李四=[88], 张三=[90, 80, 100]}
Multimap key为HashMap, value为HashSet: {李四=[88], 张三=[80, 100, 90]}
Multimap key为LinkedHashMap, value为LinkedList: {张三=[90, 80, 100], 李四=[88]}
Multimap key为LinkedHashMap, value为LinkedHashMap: {张三=[90, 80, 100], 李四=[88]}
Multimap key为TreeMap, value为TreeSet: {张三=[80, 90, 100], 李四=[88]}
Multimap key为ImmutableMap, value为ImmutableList: {张三=[90, 80, 100], 李四=[88]}
Multimap key为ImmutableMap, value为ImmutableSet: {张三=[90, 80, 100], 李四=[88]}
Multimap 获取值集合: [90, 80, 100]
Multimap 获取不存在的Key值集合: []
Multimap 被影响: {李四=[88], 张三=[90, 80, 100, 60]}
Multimap 大小:5
Multimap 是否为空: false
Multimap 包含key: true
Multimap 包含value: true
Multimap 包含key-value对: true
Multimap 替换value: {李四=[88], 张三=[10, 20, 30]}
Multimap 根据key-value删除: {李四=[88], 张三=[20, 30]}
Multimap 根据key删除: [20, 30]
Multimap 获取key集合(HashSet): [李四]
Multimap 获取key集合(MultiSet): [李四]
遍历key-value开始--------------------------
李四 : 88
遍历key-value结束--------------------------
Multimap 转换为Map<K, Collection<V>>: {李四=[88]}
```
#### 6. RangeMap - 范围映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#684335507)
  官方注释翻译:从不相交的非空范围到非 null 值的映射。查询查找与包含指定键的范围(如果有)关联的值。
  示例代码(需求:考试成绩分类):
```swift
Copy// if-else
int score = 88;
String rank;
if (0 <= score && score < 60) {
rank = "不及格";
} else if (60 <= score && score <= 84) {
rank = "及格";
} else if (84 < score && score <= 100) {
rank = "优秀";
} else {
rank = "无效";
}
System.out.println("if-else 获取值: " + rank);
// 创建RangeMap, 基于TreeMap红黑树实现
RangeMap<Integer, String> treeRangeMap = TreeRangeMap.create();
treeRangeMap.put(Range.closedOpen(0, 60), "不及格");
treeRangeMap.put(Range.closed(60, 84), "及格");
treeRangeMap.put(Range.openClosed(84, 100), "优秀");
treeRangeMap.put(Range.lessThan(0), "无效");
treeRangeMap.put(Range.greaterThan(100), "无效");
rank = treeRangeMap.get(score);
System.out.println("\nRangeMap 获取值: " + rank);
// 创建不可变RangeMap, 无法新增、更新或删除
ImmutableRangeMap<Integer, String> immutableRangeMap = ImmutableRangeMap.<Integer, String>builder()
.put(Range.closedOpen(0, 60), "不及格")
.put(Range.closed(60, 84), "及格")
.put(Range.openClosed(84, 100), "优秀")
.put(Range.lessThan(0), "无效")
.put(Range.greaterThan(100), "无效")
.build();
rank = immutableRangeMap.get(score);
System.out.println("\nImmutableRangeMap 获取值: " + rank);
// 获取key-value对
Map.Entry<Range<Integer>, String> entry = treeRangeMap.getEntry(88);
System.out.println("\nRangeMap 获取key-value对: " + entry.getKey() + " : " + entry.getValue());
// 返回不可变的升序的Map
Map<Range<Integer>, String> asMapOfRanges = treeRangeMap.asMapOfRanges();
System.out.println("\nRangeMap 不可变的升序的Map: " + asMapOfRanges);
// 返回不可变的降序的Map
Map<Range<Integer>, String> asDescendingMapOfRanges = treeRangeMap.asDescendingMapOfRanges();
System.out.println("\nRangeMap 不可变的降序的Map: " + asDescendingMapOfRanges);
// 相连范围合并
RangeMap<Integer, String> treeRangeMap2 = TreeRangeMap.create();
treeRangeMap2.putCoalescing(Range.closedOpen(0, 60), "不及格");
treeRangeMap2.putCoalescing(Range.closed(60, 84), "及格");
treeRangeMap2.putCoalescing(Range.openClosed(84, 100), "及格"); // 或者 [60..84]范围合并
treeRangeMap2.putCoalescing(Range.lessThan(0), "无效");
treeRangeMap2.putCoalescing(Range.greaterThan(100), "无效");
System.out.println("\nRangeMap 不合并相连范围: " + treeRangeMap.asMapOfRanges());
System.out.println("RangeMap 合并相连范围: " + treeRangeMap2.asMapOfRanges());
// 最小范围
Range<Integer> span = treeRangeMap.span();
System.out.println("\nRangeMap 最小范围: " + span);
// 子范围Map
RangeMap<Integer, String> subRangeMap = treeRangeMap.subRangeMap(Range.closed(70, 90));
System.out.println("\nRangeMap 子范围Map: " + subRangeMap);
// 合并范围
treeRangeMap.merge(Range.closed(60, 100), "及格", (s, s2) -> s2);
System.out.println("\nRangeMap 合并Map: " + treeRangeMap);
// 移除范围
treeRangeMap.remove(Range.open(90, 95));
System.out.println("\nRangeMap 移除范围: " + treeRangeMap);
// 清除所有范围
treeRangeMap.clear();
System.out.println("\nRangeMap 清除所有范围: " + treeRangeMap);
```
  执行结果:
```javascript
Copyif-else 获取值: 优秀
RangeMap 获取值: 优秀
ImmutableRangeMap 获取值: 优秀
RangeMap 获取key-value对: (84..100] : 优秀
RangeMap 不可变的升序的Map: {(-..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+)=无效}
RangeMap 不可变的降序的Map: {(100..+)=无效, (84..100]=优秀, [60..84]=及格, [0..60)=不及格, (-..0)=无效}
RangeMap 不合并相连范围: {(-..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+)=无效}
RangeMap 合并相连范围: {(-..0)=无效, [0..60)=不及格, [60..100]=及格, (100..+)=无效}
RangeMap 最小范围: (-..+)
RangeMap 子范围Map: {[70..84]=及格, (84..90]=优秀}
RangeMap 合并Map: [(-..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=及格, (100..+)=无效]
RangeMap 移除范围: [(-..0)=无效, [0..60)=不及格, [60..84]=及格, (84..90]=及格, [95..100]=及格, (100..+)=无效]
RangeMap 清除所有范围: []
```
#### 7. ClassToInstanceMap - 类型映射到实例Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#85873049)
  官方注释翻译:映射,其每个条目将一个 Java 原始类型 映射到该类型的实例。除了实现 Map之外还提供额外的类型安全操作 putInstance 和 getInstance 。与任何其他 Map<Class, Object>映射一样,此映射可能包含基元类型的条目,并且基元类型及其相应的包装器类型可以映射到不同的值。
示例代码需求缓存Bean(不交给Spring管理自己管理Bean)
```csharp
Copyclass UserBean {
private final Integer id;
private final String username;
public UserBean(Integer id, String username) {
this.id = id;
this.username = username;
}
@Override
public String toString() {
return "UserBean{" + "id=" + id + ", username='" + username + '\'' + '}';
}
}
// 创建Bean
UserBean userBean = new UserBean(1, "张三");
// HashMap
HashMap<Class, Object> hashMap = new HashMap<>();
hashMap.put(UserBean.class, userBean);
// 获取值,需要强转
UserBean value = (UserBean) hashMap.get(UserBean.class);
System.out.println("HashMap 获取对象实例: " + value);
System.out.println("HashMap 获取对象实例等于创建的Bean: " + (value == userBean));
// 创建ClassToInstanceMap
ClassToInstanceMap<Object> classToInstanceMap = MutableClassToInstanceMap.create();
classToInstanceMap.putInstance(UserBean.class, userBean);
// 获取值,无需强转
UserBean value2 = classToInstanceMap.getInstance(UserBean.class);
System.out.println("\nClassToInstanceMap 获取对象实例: " + value2);
System.out.println("ClassToInstanceMap 获取对象实例等于创建的Bean: " + (value2 == userBean));
// 创建不可变ClassToInstanceMap, 无法新增、更新或删除
ClassToInstanceMap<UserBean> immutableClassToInstanceMap = ImmutableClassToInstanceMap.<UserBean>builder()
.put(UserBean.class, userBean)
.build();
// 获取值,无需强转
UserBean value3 = immutableClassToInstanceMap.getInstance(UserBean.class);
System.out.println("\nImmutableClassToInstanceMap 获取对象实例: " + value3);
System.out.println("ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: " + (value3 == userBean));
// 限制类型避免使用HashMap存储对象时因为使用Object值类型而在添加缓存时需要今天类型校验
ClassToInstanceMap<Collection> classToInstanceMap1 = MutableClassToInstanceMap.create();
classToInstanceMap1.put(ArrayList.class, new ArrayList());
classToInstanceMap1.put(HashSet.class, new HashSet());
// 编译保存: 'put(java.lang.Class<? extends java.util.@org.checkerframework.checker.nullness.qual.NonNull Collection>, java.util.Collection)' in 'com.google.common.collect.MutableClassToInstanceMap' cannot be applied to '(java.lang.Class<java.util.HashMap>, java.util.HashMap)'
// classToInstanceMap1.put(HashMap.class, new HashMap());
```
  执行结果:
```bash
CopyHashMap 获取对象实例: UserBean{id=1, username='张三'}
HashMap 获取对象实例等于创建的Bean: true
ClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'}
ClassToInstanceMap 获取对象实例等于创建的Bean: true
ImmutableClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'}
ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: true
```