
本文共 3350 字,大约阅读时间需要 11 分钟。
Map 与泛型 - Java 开发指南
Map是一个高效存储键值对的数据结构,在应用开发中扮演着重要角色。本文将详细介绍Map的实现方式、常见实现类以及使用场景,并深入探讨Java中的泛型概念。
Map 的本质
Map是一种数据结构,用于存储键值对。每个键只能对应一个唯一的值,但值可以是多个键映射到它。Map的特点是键的存取是无序的,除非是LinkedHashMap这种有序的实现。此外,Map不允许键重复,但允许值重复。
HashMap 的特点
HashMap是最常用的Map实现类,基于哈希表实现,具有以下特点:
- 线程不安全:适合单线程环境。
- 可以存储null键:但null键不能作为Map的值。
- 扩容方式:当存储元素时,如果哈希溢出或超过负载因子,会扩容,扩容时会将Map的长度翻倍。
![(Map的哈希存储方式)] Map中的键通过哈希值存储,存取时快速定位,若链表长度超过8时会优化为红黑树。
Hashtable 的特点
Hashtable与HashMap类似,但具有线程安全性。使用Hashtable时,所有操作都需进行同步。另外,Hashtable不允许键或值为null,这在处理空值时需要特别注意。
- 线程安全:适合多线程环境的数据共享需求。
- 不允许null键和值:在使用时需注意这一限制。
TreeMap 的特点
TreeMap的特点是基于红黑树实现,键的存储和取出有序。 TreeMap不仅支持自然排序,还支持定制排序、逆序排序以及树形结构,可根据需求进行扩展。
- 自然排序或定制排序:默认为自然排序,支持定制键的比较逻辑。
- TreeEntry结构:Store为节点,包含键和值,树形结构决定了查找效率。
ConcurrentHashMap 的特点
ConCurrentHashMap是针对多线程环境优化的Map实现类,它采用多个哈希链表的方式实现锁粗化,解除简单偏向性的锁并发效率瓶颈。
- 高效多线程:通过细粒化锁控制并发访问,提升性能。
- 扩容过程:在扩容时不会阻止映射操作,提升性能。
LinkedHashMap 的特点
LinkedHashMap与HashMap功能相似,但有以下特点:
- 有序性:按照插入顺序存取数据。
- 双向链表:实现有序存取,支持逆序遍历。
遍历方式
Map的遍历主要有以下三种方式:
以下示例展示如何使用 ConcurrentHashMap 的entrySet()遍历键值对:
ConcurrentHashMapmap = new ConcurrentHashMap<>();map.put("age", 25);map.put("height", 180);Set > entrySet = map.entrySet();for (Map.Entry entry : entrySet) { System.out.println("key: " + entry.getKey()); System.out.println("value: " + entry.getValue());}
Properties 的应用
Properties是一个特殊的Hashtable,用于存储键值对的应用配置文件,主要用于减少硬编码依赖,提高程序的灵活性。
Properties 的主要特点
- 键值对类型:键和值都为String类型,限定了 Properties 使用范围。
- 配置文件格式:支持 .properties、 .xml、 .ini、 .yaml 等格式的配置文件读取和解析。
- 易于维护:通过 separated by newline 的格式,支持Unicode编码的配置文件完整性维护。
使用 Properties 读取配置文件
想要将配置文件中的数据读取到程序中,可以按照以下步骤进行:
以下是一个典型的读取和保存配置文件示例:
import java.util.Properties;public class PropertiesTest { public static void main(String[] args) { Properties properties = new Properties(); // 设置 properties properties.setProperty("username", "root"); properties.setProperty("password", "123456"); // 保存到文件 properties.store(new FileOutputStream("application.properties"), "保存的注释"); System.out.println(properties.storeID); // 输出存储的ID }}
配置文件类型判断
配置文件的文件扩展名决定了其类型:
- .properties:使用 Properties 类读取和解析。
- .xml:可选使用 XML 解析器读取。
- .ini:采用 ini4j 或相应库解析。
- .yaml: 使用 snakeyaml 库解析。
泛型的应用
泛型是一种强大的编程概念,可通过指定类型增强程序的可读性和安全性。本节将探讨泛型的作用、使用方法以及注意事项。
泛型的作用
- 类型校验:开发者可以在编译阶段确保类型的正确性。
- 代码简洁性:通过泛型,可以避免强制类型转换,提升代码可读性。
- 代码扩展性:通过泛型接口,程序能够支持多种数据类型增强灵活性。
泛型的使用场景
- 泛型类:在类定义时指定一个或多个类型参数,例如 List
或 Map<K,V>。 - 泛型方法:在方法签名中定义类型参数,提升方法的通用性。
泛型的上限和下限
通过设置泛型的上限和下限,可进一步增强类型的安全性。例如:
-
返回类型:使用 extends 表示返回值的上限,可以通过扩展关系限定类型。例如:
public
T myMethod() { ... } -
参数类型:使用 super 表示类型的下限,可强制指定类型范围。例如:
public
void myMethod(T t) { ... }
泛型嵌套
泛型的嵌套使得复杂数据结构的设计成为可能。例如,以下 Set 中的元素是 Map:
Set> entrySet = ...;
泛型注意事项
- 基本数据类型不能使用泛型:如 List
发表评论
最新留言
关于作者
