在java中实现映射数据结构应优先使用java集合框架提供的map接口实现类,最常用的是hashmap,它基于哈希表实现,提供平均o(1)时间复杂度的插入、删除和查找操作,适用于大多数无需排序的场景;当需要键有序时应选择treemap,其基于红黑树实现,支持自然排序或自定义比较器,操作时间复杂度为o(log n);当需保持插入顺序或实现lru缓存时应使用linkedhashmap,它在hashmap基础上通过双向链表维护顺序,性能接近hashmap;在多线程环境下,hashmap、treemap和linkedhashmap均非线程安全,应优先选用concurrenthashmap,其采用cas和细粒度同步机制,提供高并发性能,而collections.synchronizedmap虽可提供线程安全但性能较差,仅适用于低并发场景;使用自定义对象作为键时必须正确重写hashcode()和equals()方法,并推荐使用不可变对象以避免哈希值变化导致的查找失败,合理设置hashmap的初始容量和加载因子可有效避免频繁扩容,提升性能,综上所述,根据具体需求选择合适的map实现类并理解其内部机制是高效使用映射的关键。
在Java中实现映射(Map)数据结构,我们通常不是从零开始“实现”一个Map,而是利用Java集合框架中已经提供的
Map
HashMap
TreeMap
LinkedHashMap
要使用Java的映射表,最常见也是最基础的就是
HashMap
import java.util.HashMap; import java.util.Map; public class MapPracticalExample { public static void main(String[] args) { // 声明并初始化一个HashMap,键是String类型,值是Integer类型 Map<String, Integer> studentScores = new HashMap<>(); // 添加键值对 studentScores.put("张三", 95); studentScores.put("李四", 88); studentScores.put("王五", 92); studentScores.put("张三", 98); // 如果键已存在,新值会覆盖旧值 System.out.println("学生分数表: " + studentScores); // 根据键获取值 int zhangsanScore = studentScores.get("张三"); System.out.println("张三的分数: " + zhangsanScore); // 检查Map是否包含某个键 boolean containsLisi = studentScores.containsKey("李四"); System.out.println("是否包含李四: " + containsLisi); // 检查Map是否包含某个值 boolean containsScore90 = studentScores.containsValue(90); System.out.println("是否包含分数90: " + containsScore90); // 移除键值对 studentScores.remove("王五"); System.out.println("移除王五后: " + studentScores); // 遍历Map的几种方式 System.out.println("\n遍历学生分数表:"); // 方式一:遍历entrySet(推荐,效率高) for (Map.Entry<String, Integer> entry : studentScores.entrySet()) { System.out.println("姓名: " + entry.getKey() + ", 分数: " + entry.getValue()); } // 方式二:遍历keySet,再通过键获取值 System.out.println("\n遍历学生姓名:"); for (String name : studentScores.keySet()) { System.out.println("姓名: " + name + ", 分数: " + studentScores.get(name)); } // 方式三:遍历values System.out.println("\n遍历学生分数(仅值):"); for (Integer score : studentScores.values()) { System.out.println("分数: " + score); } // Java 8 引入的forEach方法 System.out.println("\n使用forEach遍历:"); studentScores.forEach((name, score) -> System.out.println("姓名: " + name + ", 分数: " + score)); } }
HashMap
HashMap
HashMap
hashCode()
立即学习“Java免费学习笔记(深入)”;
从我个人的经验来看,
HashMap
HashMap
new HashMap<>(16)
HashMap
HashMap
容量 * 加载因子
HashMap
另外,使用
HashMap
hashCode()
equals()
HashMap
put
get
hashCode()
equals()
equals()
hashCode()
HashMap
hashCode()
虽然
HashMap
TreeMap
LinkedHashMap
TreeMap
TreeMap
SortedMap
TreeMap
Comparable
Comparator
HashMap
HashMap
import java.util.TreeMap; import java.util.Comparator; // ...在某个方法内... Map<String, Integer> sortedScores = new TreeMap<>(); // 默认按键的自然顺序(字母序)排序 sortedScores.put("王五", 92); sortedScores.put("张三", 95); sortedScores.put("李四", 88); System.out.println("TreeMap (按键排序): " + sortedScores); // 输出会是:李四=88, 王五=92, 张三=95 // 也可以提供自定义Comparator Map<String, Integer> customSortedScores = new TreeMap<>(Comparator.reverseOrder()); // 按键逆序 customSortedScores.put("王五", 92); customSortedScores.put("张三", 95); customSortedScores.put("李四", 88); System.out.println("TreeMap (自定义逆序): " + customSortedScores); // 输出会是:张三=95, 王五=92, 李四=88
LinkedHashMap
LinkedHashMap
HashMap
HashMap
LinkedHashMap
HashMap
HashMap
removeEldestEntry
import java.util.LinkedHashMap; // ...在某个方法内... Map<String, Integer> insertionOrderMap = new LinkedHashMap<>(); insertionOrderMap.put("香蕉", 1); insertionOrderMap.put("苹果", 2); insertionOrderMap.put("橘子", 3); System.out.println("LinkedHashMap (插入顺序): " + insertionOrderMap); // 输出会是:香蕉=1, 苹果=2, 橘子=3 // LRU缓存示例 (访问顺序) // 构造函数参数: initialCapacity, loadFactor, accessOrder (true表示按访问顺序,false表示按插入顺序) Map<String, Integer> lruCache = new LinkedHashMap<>(16, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) { return size() > 3; // 当Map大小超过3时,移除最老的(或最久未访问的)元素 } }; lruCache.put("A", 1); lruCache.put("B", 2); lruCache.put("C", 3); System.out.println("LRU Cache (初始): " + lruCache); // A, B, C lruCache.get("A"); // 访问A,A会移动到链表末尾(最新访问) lruCache.put("D", 4); // 插入D,C会被移除(最久未访问) System.out.println("LRU Cache (访问A后插入D): " + lruCache); // B, C, A, D (如果按访问顺序) 或 B, A, D (如果C被移除了) // 实际上是 B, C, A,然后D进来,B被移除,变成 C, A, D // 实际输出会是:C=3, A=1, D=4
这里要稍微纠正一下,
LinkedHashMap
accessOrder
true
get
removeEldestEntry
C
A
D
默认的
HashMap
TreeMap
LinkedHashMap
ConcurrentModificationException
Collections.synchronizedMap()
Collections.synchronizedMap()
import java.util.Collections; import java.util.HashMap; Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>()); // 现在syncMap的所有操作都是线程安全的了 syncMap.put("key", 1);
缺点:这种方式的同步粒度太粗,每次操作都会锁住整个Map。在高并发场景下,这会导致严重的性能瓶颈,因为所有线程都必须等待锁释放,串行化执行。
ConcurrentHashMap
ConcurrentHashMap
java.util.concurrent
Collections.synchronizedMap()
synchronized
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class ConcurrentMapExample { public static void main(String[] args) throws InterruptedException { ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>(); ExecutorService executor = Executors.newFixedThreadPool(10); // 多个线程同时写入 for (int i = 0; i < 100; i++) { final int taskId = i; executor.submit(() -> { String key = "Task-" + taskId % 10; // 模拟一些键冲突 concurrentMap.compute(key, (k, v) -> (v == null) ? 1 : v + 1); // compute 方法是原子性的,可以安全地进行读改写操作 }); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES); System.out.println("ConcurrentHashMap 最终结果: " + concurrentMap); // 验证结果,通常会是 Task-X=10 System.out.println("Task-0 计数: " + concurrentMap.get("Task-0")); } }
在选择并发Map时,我个人的习惯是,如果只是偶尔有并发访问,或者并发量很低,
Collections.synchronizedMap()
ConcurrentHashMap
以上就是java代码怎样实现映射(Map)数据结构 java代码映射表的实用实现教程的详细内容,更多请关注php中文网其它相关文章!
java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号