
Java 热门面试题 200 道速记通关版 | 面试刷题 mianshiya.com
Java 中有哪些集合类?请简单介绍
Java 的集合类主要分两大派,一个是 Collection 接口下的各种实现,另一个是 Map 系的键值对结构。面试里聊到这块,重点其实是搞清楚每种集合适用的场景和底层机制。
Collection 里最常用的是 List、Set 和 Queue。
List 是有序可重复的,ArrayList 内部用数组实现,随机访问快,但中间插入删除得搬数据,性能损耗大;LinkedList 是双向链表,适合频繁增删的场景,尤其是头尾操作。
Set 不允许重复元素,HashSet 基于 HashMap 实现,查找添加都是 O(1),但不保序;LinkedHashSet 能维持插入顺序;TreeSet 则能自然排序,底层是红黑树。
Queue 一般用在任务调度,比如 ArrayDeque 是数组实现的双端队列,ConcurrentLinkedQueue 是无锁线程安全队列,DelayQueue 适合定时任务。
Map 才是脏活累活的主力。HashMap 最常见,数组 + 链表/红黑树结构,非线程安全,但性能好;Hashtable 就是老古董了,方法全 synchronized,基本被 ConcurrentHashMap 取代,后者用了分段锁 + CAS,在高并发下能扛住压力。
LinkedHashMap 能记住插入顺序,适合做 LRU 缓存;TreeMap 支持按键排序。
1)ArrayList 查找快,增删慢
2)LinkedList 增删快,查找慢
3)HashMap 性能高,并发用 ConcurrentHashMap
4)需要排序考虑 TreeSet / TreeMap
5)讲究插入顺序用 LinkedHashMap
MySQL 的索引类型有哪些?
MySQL 的索引类型主要看存储引擎支持,最常用的是 InnoDB,它的索引结构基于 B+ 树。
1)主键索引(聚簇索引)
行数据和主键一起存储在 B+ 树的叶子节点,物理顺序和主键顺序一致。每张表只能有一个,查询效率最高,范围查询也快。
2)二级索引(普通索引)
非主键列上的索引,B+ 树叶子节点存的是主键值。查非主键字段会先走二级索引找到主键,再回表查聚簇索引,这个过程叫回表。
3)唯一索引
和二级索引类似,但要求列值唯一,允许一个 NULL。创建唯一约束时自动建这种索引。
4)联合索引
多个列组合的索引,遵循最左前缀原则。比如 (a, b, c) 能命中 a、(a,b)、(a,b,c),但不能用 b 单独查。
5)全文索引
用于文本内容的关键词搜索,支持 MATCH AGAINST 语法。MyISAM 和 InnoDB 都支持,但使用场景不多,一般用 Elasticsearch 或 OpenSearch 替代。
6)前缀索引
对字符串前 N 个字符建索引,节省空间。比如 index(email(10)),但会影响区分度,可能增加扫描行数。
覆盖索引是个重要优化点。如果查询的字段都在索引里,压根不经过回表,直接从二级索引返回数据,速度很快。比如给 (name, age) 建联合索引,select name, age from t where name=? 就能覆盖。
MySQL 索引的最左前缀匹配原则是什么?
当你的 SQL 查询条件用到了联合索引,但不是从第一个字段开始,也不是连续使用时,能不能命中索引,就得看最左前缀匹配原则。
这条规则的意思是,MySQL 会一直向右匹配直到遇到范围查询(比如 >、<、BETWEEN、LIKE)或者没有使用的列为止,中间不能断。
举个例子,你有个联合索引 (a, b, c),那么下面这些查询能走索引: 1)只查 a 2)查 a 和 b 3)查 a、b、c
但如果查的是 b 单独,或者 b 和 c,压根不经过 a,那这个联合索引就用不上。因为不符合“最左”这个前提。
特别注意范围查询的影响。比如 WHERE a = 1 AND b > 2 AND c = 3,虽然三个字段都用了,但因为 b 是范围,c 就没法再利用索引了。也就是说,范围查询后面的列不会走索引。
实际开发中,像 user_id 和 create_time 这种高频组合,如果你把 create_time 放前面,而查询经常是等值查 user_id + 范围查时间,那索引顺序错了就搞不定查询性能。
所以建联合索引的时候,顺序很关键:等值查询放前面,范围查询放后面,并且尽量让高频字段靠左。
在 MySQL 中建索引时需要注意哪些事项?
索引不是建得越多越好,搞不好反而拖慢写入性能。每条 INSERT、UPDATE 都要维护索引结构,尤其是 B+ 树的分裂合并,成本不低。
1)选择区分度高的列作为索引键。比如用户表用 user_id 比用 gender 强多了,后者只有两个值,查起来几乎全表扫。
2)联合索引注意最左前缀原则。比如你建了 (a, b, c) 的组合索引,查询条件必须从 a 开始,只查 b 或 c 压根不经过这个索引。
3)避免在索引列上做计算或函数操作。像 WHERE YEAR(create_time) = 2023 这种写法,即使 create_time 有索引也用不上,得改成范围查询。
4)覆盖索引能显著提升性能。如果查询字段都在索引里,MySQL 直接从 B+ 树的叶子节点取数据,不用回表查主键索引,减少 IO。
5)字符串字段别全建索引,太占空间。比如 VARCHAR(255) 可以只对前 10 个字符建前缀索引
