一、基础问题
-
HashMap扩容机制
- 触发条件:当元素数量超过
容量 * 负载因子(默认0.75)
时触发扩容。 - 扩容过程:
- 新容量为旧容量的2倍(如16 → 32)。
- 遍历旧数组,重新计算每个元素的哈希值,分配到新数组的对应位置。
- Java 8优化:链表长度≥8时转为红黑树,提高查询效率。
- 示例:
HashMap<Integer, String> map = new HashMap<>(16); // 当插入第13个元素(16*0.75=12)时触发扩容 for (int i = 0; i < 13; i++) { map.put(i, "value" + i); }
- 触发条件:当元素数量超过
-
Spring循环依赖解决
- 三级缓存机制:
- singletonObjects:完整Bean实例。
- earlySingletonObjects:提前暴露的原始Bean(未填充属性)。
- singletonFactories:Bean工厂,用于生成代理对象(如AOP场景)。
- 流程:
- Bean A实例化后,放入三级缓存(
singletonFactories
)。 - 填充A的属性时发现依赖Bean B,触发B的实例化。
- B填充属性时从三级缓存获取A的工厂,生成A的代理对象。
- B初始化完成后,A完成属性填充。
- Bean A实例化后,放入三级缓存(
- 限制:仅支持Setter注入,构造器注入无法解决循环依赖。
- 三级缓存机制:
二、设计题
-
短链系统设计
- 核心组件:
- 发号器:使用Snowflake算法生成唯一ID,转换为Base62短码(如
https://s.com/abc123
)。 - 缓存层:Redis缓存热点短链(Key:短码,Value:原始URL),过期时间24小时。
- 存储层:MySQL分库分表(按短码哈希分片),字段包括
short_code
、origin_url
、expire_time
。
- 发号器:使用Snowflake算法生成唯一ID,转换为Base62短码(如
- 高并发处理:
- 布隆过滤器拦截无效短码查询。
- 异步写入数据库(MQ削峰)。
- 核心组件:
-
微信红包架构
- 预分配金额:
- 二倍均值算法:剩余金额为M,剩余人数为N,每次分配金额范围为
[1, 2M/N)
。
def allocate_red_packet(total_amount, num): result = [] for i in range(num-1): avg = total_amount / (num - i) * 2 money = random.uniform(0.01, avg) result.append(round(money, 2)) total_amount -= money result.append(round(total_amount, 2)) return result
- 二倍均值算法:剩余金额为M,剩余人数为N,每次分配金额范围为
- 抢红包流程:
- 用户抢红包时,Redis原子操作扣减预分配金额(
DECRBY
)。 - 记录明细到分库分表(按用户ID哈希)。
- 用户抢红包时,Redis原子操作扣减预分配金额(
- 防超发:数据库唯一索引(红包ID + 用户ID) + 异步对账任务。
- 预分配金额:
三、算法问题
-
Top K问题(堆排序)
- 步骤:
- 构建大小为K的小顶堆。
- 遍历数组,若元素 > 堆顶,替换堆顶并调整堆。
- 最终堆中元素即为Top K。
- 时间复杂度:O(n log K)。
- 代码示例:
public int[] topK(int[] nums, int k) { PriorityQueue<Integer> heap = new PriorityQueue<>(); for (int num : nums) { if (heap.size() < k) { heap.offer(num); } else if (num > heap.peek()) { heap.poll(); heap.offer(num); } } return heap.stream().mapToInt(i -> i).toArray(); }
- 步骤:
-
LRU缓存(LinkedHashMap)
- 实现原理:
- 继承
LinkedHashMap
,设置accessOrder=true
,使最近访问的元素移至链表尾部。 - 重写
removeEldestEntry
方法,当容量超限时移除链表头部元素。
- 继承
- 代码示例:
class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int capacity; public LRUCache(int capacity) { super(capacity, 0.75f, true); this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > capacity; } }
- 优化:线程安全版本需结合
ConcurrentHashMap
和同步锁。
- 实现原理:
四、总结与扩展
- HashMap:关注Java 8的红黑树优化和哈希冲突解决策略。
- Spring循环依赖:理解三级缓存与AOP代理的交互细节。
- 短链系统:重点设计发号器与高可用存储方案。
- 微信红包:强调预分配算法和原子扣减逻辑。
- 算法:掌握堆排序在数据流场景的应用,LRU的变种实现(如LFU)。
通过结合代码示例和架构图,可清晰展示技术深度与系统设计能力。