西安专业做网站的,龙岩网络三大巨头,wordpress订单接收插件,毕业设计网站建设题目1.前言
Java 中的双列集合主要指的是可以存储键值对的集合类型#xff0c;其中最常用的包括 Map 接口及其实现类。这些集合允许你以键值对的形式存储和管理数据#xff0c;提供了便捷的按键访问值的方式。 2. HashMap
HashMap 是基于哈希表实现的 Map 接口的类#xff0c… 1.前言
Java 中的双列集合主要指的是可以存储键值对的集合类型其中最常用的包括 Map 接口及其实现类。这些集合允许你以键值对的形式存储和管理数据提供了便捷的按键访问值的方式。 2. HashMap
HashMap 是基于哈希表实现的 Map 接口的类允许存储键值对支持 null 键和 null 值。它提供了 O(1) 时间复杂度的插入、删除和查找操作但不保证映射顺序。
由键决定无序、不重复、无索引。
底层数据结构: 数组 链表 / 红黑树JDK8其中一个链表超过8并且数组长度不低于64转换为红黑树。通过哈希函数将键映射到数组索引解决哈希冲突的链表或红黑树存储。初始容量是16扩容因子是0.75。扩容扩大两倍(持续保持2^n次方的容量)。 多个输入对应相同输出hash冲突。
为什么要转换成红黑树
HashMap变红黑树主要用于防患于未然防止有些人造一些恶劣数据。正常存20万个单词都不会有链表超过8。
为什么hash表的容量是2^n次方?
1.能使用2^n
对于程序来说涉及位运算符相对来说都是高效的因为计算机底层是以二进制存储的二进制是天然的位运算符操作容器。
2.高低位异或计算hash值
因为二进制和容器容量正好对应只需要看后几位高位根本用不上。2^n次方看后n位。
低位相同的哈希码在高位不同的情况下会产生hash冲突。通过高16位和低16位异或运算能够让存入的位置由高位的参与决定。
负载因子的概念 负载因子load factor是哈希表的一个重要概念其定义为哈希表的元素数量除以桶数量用于衡量哈希冲突的严重程度也常作为哈希表扩容的触发条件。例如在 Java 中当负载因子超过 0.75 时系统会将哈希表扩容至原先的 2 倍。 容易想到哈希表容量 越大多个 key 被分配到同一个桶中的概率就越低冲突就越少。因此我们可以通过扩容哈希表来减少哈希冲突。
类似于数组扩容哈希表扩容需将所有键值对从原哈希表迁移至新哈希表非常耗时并且由于哈希表容量 capacity 改变我们需要通过哈希函数来重新计算所有键值对的存储位置这进一步增加了扩容过程的计算开销。为此编程语言通常会预留足够大的哈希表容量防止频繁扩容。 HashSet 的加载因子被设置为 0.75 是为了在空间利用率和性能之间取得平衡。这个值能够使得哈希表在大多数情况下既能够有效地利用内存又能够保持较好的查询性能是经过权衡和实验确定的合理选择。 // 创建一个HashMap
MapString, Integer hashMap new HashMap();// 添加键值对
hashMap.put(apple, 1);
hashMap.put(banana, 2);// 获取值
int value hashMap.get(apple);
System.out.println(value); // 输出: 13. LinkedHashMap: LinkedHashMap 继承自 HashMap保留了元素插入顺序即按照插入顺序迭代元素。可选择按访问顺序LRU 缓存算法排序。 由键决定有序、不重复、无索引。 底层数据结构: 哈希表 双向链表。双向链表维护插入顺序或访问顺序。 与HashMap不同的是存和取的顺序相同
原理每个键值对元素之间又额外的多了一个双链表的机制记录存储的顺序。 在添加第一个元素的时候会记录第一个元素的地址值然后取的时候根据第一个元素的地址值找到头节点依次进行取元素。
// 创建一个LinkedHashMap保持插入顺序
MapString, Integer linkedHashMap new LinkedHashMap(16, 0.75f, true);// 添加键值对
linkedHashMap.put(apple, 1);
linkedHashMap.put(banana, 2);// 获取值更新访问顺序
int value linkedHashMap.get(apple);
System.out.println(value); // 输出: 14. TreeMap: TreeMap 基于红黑树实现可根据键的自然顺序或自定义比较器排序。元素有序存储提供灵活的自定义排序功能。 底层数据结构: 红黑树。自平衡二叉查找树保证有序性。 对于原理和TreeSet相似在上一篇已经讲解过了这里就不过多介绍了。
// 创建一个TreeMap根据键的自然顺序排序
MapString, Integer treeMap new TreeMap();// 添加键值对
treeMap.put(apple, 1);
treeMap.put(banana, 2);// 获取值
int value treeMap.get(apple);
System.out.println(value); // 输出: 15. Hashtable: Hashtable 是早期的 Map 类与 HashMap 类似但线程安全。由于同步开销大推荐使用 ConcurrentHashMap 替代。 底层数据结构: 数组 链表。通过哈希函数将键映射到数组索引使用链表解决冲突。
// 创建一个Hashtable
MapString, Integer hashtable new Hashtable();// 添加键值对
hashtable.put(apple, 1);
hashtable.put(banana, 2);// 获取值
int value hashtable.get(apple);
System.out.println(value); // 输出: 1面试题谈谈HashMap和HashTable的区别
线程安全方面 HashTable是线程安全的(底层使用了全局同步锁)HashMap是线程不安全的因此可以得出HashMap的性能比较好数据结构的实现 java8以后HashMap使用数组链表红黑树组成(当节点高于7转换为红黑树) HashTable是数组链表 初始容量 HashMap初始容量是16HashTable初始容量是11hash算法 HashMap的散列算法是对key的hashcode进行二次散列从而避免key的分布不均匀影响性能。HashTable是hashcode对数组的长度取模
6. ConcurrentHashMap: ConcurrentHashMap 针对高并发设计通过分段锁Segmented lock实现线程安全。性能优于 Hashtable在多线程环境中使用较为合适。 底层数据结构: 分段锁 数组 链表 / 红黑树JDK8。每个段Segment独立锁定允许多线程并发访问不同段的数据。
// 创建一个ConcurrentHashMap
MapString, Integer concurrentHashMap new ConcurrentHashMap();// 添加键值对
concurrentHashMap.put(apple, 1);
concurrentHashMap.put(banana, 2);// 获取值
int value concurrentHashMap.get(apple);
System.out.println(value); // 输出: 1这些双列集合类在不同的场景中提供了各自的优势根据需求选择合适的实现类可以提高数据的管理效率和性能。
面试题HashTable为什么会被ConcurrentHashMap替代
ConcurrentHashMap 可以替代 Hashtable 的几个主要原因包括 并发性能优化 ConcurrentHashMap 使用了分段锁Segmented lock或 CAS 操作来实现线程安全而 Hashtable 使用了全局锁。这意味着 ConcurrentHashMap 在多线程并发访问时可以支持更高的并发度因为不同段Segment的数据可以并行操作而 Hashtable 的所有操作都是同步的。 更好的扩展性 ConcurrentHashMap 在设计上采用了分段锁策略这样在多线程情况下不同段的数据可以并行处理从而减少了锁竞争提高了并发访问效率。相比之下Hashtable 的同步操作可能会导致线程争用限制了扩展性和性能。 更好的迭代性能 在迭代时ConcurrentHashMap 可以允许在不进行任何同步的情况下进行读取操作而 Hashtable 则要求在整个表上进行锁定。这意味着在迭代期间ConcurrentHashMap 的性能更好因为它不会被其他线程的修改所阻塞。 允许空键和空值 ConcurrentHashMap 允许 null 键和 null 值的存在而 Hashtable 不允许。这在某些场景下可能更为灵活。
综上所述ConcurrentHashMap 在设计和实现上优于 Hashtable尤其是在高并发环境中能够提供更好的性能和扩展性因此在大多数情况下推荐使用 ConcurrentHashMap 而不是 Hashtable。 7. Peoperties
Properties 是 Java 中处理配置文件的一个常用类它继承自 HashtableObject, Object也实现了 MapObject, Object 接口。主要用于存储键值对形式的配置信息通常用于读取和写入属性文件.properties 文件)。
Properties 类在 Java 中广泛应用于配置文件的读写
使用load()方法从一个输入流中加载属性或者使用store()方法将属性保存到输出流中。
主要特点和用途 存储键值对 Properties 对象存储的是字符串键和值的映射关系键和值都必须是字符串类型。 加载和存储属性文件 Properties 可以从文件中加载配置信息也可以将配置信息写入文件。常见的配置文件格式是 .properties 文件它采用 keyvalue 的格式存储配置信息。 默认的读写方法 提供了便捷的方法来加载和存储属性文件如 load() 和 store() 方法。 默认值支持 可以设置默认值当请求的属性不存在时返回默认值。 线程安全性 Properties 继承自 Hashtable因此默认不是线程安全的。在多线程环境下可以通过同步措施来保证线程安全。
基本操作示例
创建和设置属性
Properties prop new Properties();
prop.setProperty(database.url, jdbc:mysql://localhost:3306/mydatabase);
prop.setProperty(database.user, username);
prop.setProperty(database.password, password);从文件加载属性
try (FileInputStream fis new FileInputStream(config.properties)) {prop.load(fis);
} catch (IOException e) {e.printStackTrace();
}将属性存储到文件
try (FileOutputStream fos new FileOutputStream(config.properties)) {prop.store(fos, Database Configuration);
} catch (IOException e) {e.printStackTrace();
}获取属性值
String url prop.getProperty(database.url);
String user prop.getProperty(database.user, defaultUser); // 指定默认值
String password prop.getProperty(database.password);注意事项
字符编码默认情况下store() 方法使用 ISO 8859-1 编码不支持 Unicode 字符。如果需要支持 Unicode可以使用 Writer 参数的 store(Writer writer, String comments) 方法并指定合适的字符编码。属性文件格式 .properties 文件使用简单的 keyvalue 格式存储数据不支持复杂的数据结构或注释可以用 # 开头注释。默认值处理 如果请求的属性不存在getProperty(key) 方法返回 null可以使用 getProperty(key, defaultValue) 指定默认值。 8. 总结 双列集合在软件开发中扮演关键角色通过键值对的方式存储和管理数据支持快速的插入、删除和查找操作适用于各种应用场景如配置管理、缓存实现和关联数据管理。Java中的Map接口及其实现类如HashMap、TreeMap等提供了多样化选择开发人员可以根据需求选择最适合的实现以提高性能和效率。这些特性使得双列集合成为处理复杂数据结构和优化数据访问的重要工具。