Java热门面试题200
Java面试题
1.说说Java中的HashMap原理?
-
HashMap 是一个基于哈希表的数据结构,通过键的哈希值快速定位存储位置。
底层由数组+链表(红黑树JDK1.8)实现,通过键的hashCode()方法计算出哈希值,然后由哈希值和数组长度得出一个索引(公式:
index = (数组长度 - 1) & hash(key)
),发送哈希冲突时会使用链表或者红黑树来存储这些冲突的键值对。当数组长度不够时,会进行扩容至原来的2倍。特点: 无序 允许空键和空值 非线程安全 需要线程安全,可以用
ConcurrentHashMap
2.Java中'ConcurrentHashMap' 1.7和1.8之间有哪些区别?
- Java 1.7 的
ConcurrentHashMap
像是一个大仓库,分成多个小房间(Segment),每个房间有自己的锁。 - Java 1.8 的
ConcurrentHashMap
更像是一个大仓库,每个货架(桶)有自己的锁,锁的粒度更小,效率更高。 - Java 1.8 还引入了红黑树,解决了链表过长时查找效率低的问题。
3.为什么JDK1.8对HashMap 进行了红黑树的改动?
-
JDK 1.7 的
HashMap
在链表过长时,性能会变差。 -
JDK 1.8 引入了红黑树,当链表太长时,把它变成一棵树,查找速度更快。
-
红黑树的引入是为了解决极端情况下的性能问题,同时平衡了时间和空间的开销。
注:
- 链表转红黑树:当链表长度超过 8 时,链表会转换为红黑树。
- 红黑树转链表:当红黑树的节点数减少到 6 时,红黑树会转换回链表。
4.JDK1.8 对 HashMap 除了红黑树还进行了哪些改动?
JDK 1.8 对
HashMap
的改进主要集中在以下几个方面:- 性能优化:引入红黑树、优化哈希算法、改进扩容机制。
- 安全性提升:链表插入方式改为尾插法,避免死循环。
- 功能增强:支持函数式编程,提供更丰富的 API。
- 代码优化:重构代码,提高可读性和可维护性。
这些改动使得
HashMap
在 JDK 1.8 中性能更高、更安全、更易用。
5.Java 中有哪些集合类?请简单介绍
Java中集合主要分为两大类:Collection接口和Map接口,前者存储对象的集合类,后者存储的是键值对。
Collection接口下又分为List Set Queue .
List接口(有序可重复):
常用实现类:ArrayList:基于动态数组实现,查询快,增删慢。
LinkedList:基于双向链表实现,增删快,查询慢。
Vector:线程安全的动态数组,性能较差(已被 ArrayList 取代)。
Set:无序不可重复。
HashSet:基于哈希表实现,查询速度快,元素无序。 LinkedHashSet:基于哈希表和链表实现,元素按插入顺序排列。 TreeSet:基于红黑树实现,元素按自然顺序或自定义顺序排序。
- Java 1.7 的
(1)Map(键不可重复)
- 特点:键值对存储,键不允许重复,值可以重复。
- 常用实现类:
- HashMap:基于哈希表实现,键值对无序,查询速度快。
- LinkedHashMap:基于哈希表和链表实现,键值对按插入顺序排列。
- TreeMap:基于红黑树实现,键值对按自然顺序或自定义顺序排序。
- Hashtable:线程安全的哈希表,性能较差(已被
HashMap
取代)。 - ConcurrentHashMap:线程安全的哈希表,性能优于
Hashtable
。
5.MySQL索引的最左前缀匹配原则是什么?
1. 什么是复合索引?
复合索引是指对表中多个列组合起来创建的索引。比如:
CREATE INDEX idx_name_age ON users(name, age);
这里创建了一个复合索引,包含 name
和 age
两个列。
2. 最左前缀匹配原则是什么?
最左前缀匹配原则是指:在使用复合索引时,MySQL 会从索引的最左边开始匹配查询条件。也就是说,查询条件必须包含复合索引的最左边的列,才能利用索引。
3. 举个例子
假设有一个复合索引 idx_name_age
,包含两列:name
和 age
。
(1)能使用索引的情况
-
查询条件包含最左列
name
:SELECT * FROM users WHERE name = 'Alice';
这里使用了
name
列,符合最左前缀匹配原则,索引生效。 -
查询条件包含最左列
name
和第二列age
:SELECT * FROM users WHERE name = 'Alice' AND age = 25;
这里同时使用了
name
和age
列,符合最左前缀匹配原则,索引生效。
(2)不能使用索引的情况
-
查询条件不包含最左列
name
:SELECT * FROM users WHERE age = 25;
这里只使用了
age
列,没有使用最左列name
,不符合最左前缀匹配原则,索引失效。 -
查询条件跳过了最左列
name
:SELECT * FROM users WHERE age = 25 AND name = 'Alice';
虽然查询条件中包含了
name
和age
,但name
不是最左列的条件,索引仍然可能失效(取决于 MySQL 的优化器)。
4. 特殊情况:部分匹配
如果查询条件只包含复合索引的一部分列,但仍然从最左列开始匹配,索引仍然可以部分生效。
例如:
SELECT * FROM users WHERE name = 'Alice';
这里只使用了 name
列,索引仍然生效。
5. 总结
- 最左前缀匹配原则:使用复合索引时,查询条件必须从索引的最左列开始匹配。
- 能使用索引的情况:
- 查询条件包含最左列。
- 查询条件包含最左列及其后的列。
- 不能使用索引的情况:
- 查询条件不包含最左列。
- 查询条件跳过了最左列。
6. 通俗理解
可以把复合索引想象成一本字典:
- 字典的目录是按照字母顺序排列的(比如 A-Z)。
- 如果你只知道第二个字母(比如 B),而没有第一个字母(比如 A),你是无法快速查找的。
- 只有从第一个字母开始查找,才能快速定位到目标。
6.数据库的脏读、不可重复读和幻读分别是什么?
- 脏读:读到别人没写完的草稿。
- 不可重复读:同一件事,两次看到的结果不一样。就像你第一次看一本书的某一页,内容是 A;第二次再看时,内容被改成了 B。
- 幻读:同一范围的数据,两次查询的结果集不一样。就像你第一次数教室里有 10 个人,第二次数时突然多了一个人。
7.MySQL的存储引擎有哪些?它们之间有什么区别?
-
需要事务支持:选择 InnoDB。
-
读多写少,不需要事务:选择 MyISAM。
-
临时数据或缓存:选择 MEMORY。
-
日志或归档数据:选择 ARCHIVE。
-
数据导入导出:选择 CSV。
-
以下是这些存储引擎的主要特点和区别:
特性 InnoDB MyISAM MEMORY ARCHIVE CSV 事务支持 支持(ACID 事务) 不支持 不支持 不支持 不支持 外键支持 支持 不支持 不支持 不支持 不支持 锁粒度 行级锁 表级锁 表级锁 行级锁 表级锁 崩溃恢复 支持(通过日志恢复) 不支持 数据丢失 不支持 不支持 存储限制 64TB 256TB 内存限制 无明确限制 文件大小限制 索引类型 聚簇索引 非聚簇索引 哈希索引 不支持索引 不支持索引 适用场景 高并发、事务性操作 读多写少、非事务性操作 临时数据、缓存 日志存储、归档数据 数据导入导出
8.MySQL 的覆盖索引是什么?
1. 什么是覆盖索引?
覆盖索引是指:一个索引包含了查询所需的所有字段,因此查询可以直接通过索引获取数据,而无需回表(即无需再去读取数据行)。
2. 覆盖索引的原理
- 通常情况下,MySQL 的查询需要两步:
- 通过索引查找数据的位置(索引扫描)。
- 根据位置去数据表中读取具体的行(回表操作)。
- 如果使用覆盖索引,查询所需的所有字段都包含在索引中,因此 MySQL 可以直接从索引中获取数据,跳过回表操作。
3. 举个例子
假设有一张表 users
,结构如下:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT,
city VARCHAR(50)
);
(1)普通索引查询
-
创建一个普通索引:
CREATE INDEX idx_name ON users(name);
-
执行查询:
SELECT name, age FROM users WHERE name = 'Alice';
- 这个查询需要两步:
- 通过索引
idx_name
找到name = 'Alice'
的行。 - 根据索引中的位置,回表读取
age
字段。
- 通过索引
- 这个查询需要两步:
(2)覆盖索引查询
-
创建一个覆盖索引:
CREATE INDEX idx_name_age ON users(name, age);
-
执行查询:
SELECT name, age FROM users WHERE name = 'Alice';
- 这个查询只需要一步:
- 通过索引
idx_name_age
直接获取name
和age
字段,无需回表。
- 通过索引
- 这个查询只需要一步:
4. 覆盖索引的好处
- 减少 I/O 操作:无需回表,减少了磁盘 I/O 操作,提高了查询性能。
- 减少 CPU 开销:索引通常比数据行小,扫描索引比扫描数据行更快。
- 适合查询优化:对于只查询少量字段的场景,覆盖索引可以显著提升性能。
5. 如何判断是否使用了覆盖索引?
在 MySQL 中,可以通过 EXPLAIN
命令查看查询的执行计划。如果 Extra
列显示 Using index
,说明使用了覆盖索引。
例如:
EXPLAIN SELECT name, age FROM users WHERE name = 'Alice';
如果输出中 Extra
列显示 Using index
,则表示使用了覆盖索引。
6. 覆盖索引的限制
- 索引大小:覆盖索引需要包含查询的所有字段,如果字段较多或字段较大,索引会占用更多存储空间。
- 写操作开销:覆盖索引会增加写操作(如
INSERT
、UPDATE
、DELETE
)的开销,因为需要维护更多的索引。
7. 通俗总结
- 覆盖索引就像一本书的目录,如果目录中已经包含了你想查找的内容,你就不需要翻到具体的页面了。
- 使用覆盖索引可以避免回表操作,提高查询性能。
9.MySQL 的索引类型有哪些?
- B-Tree 索引:万能索引,适合大多数场景。
- 哈希索引:适合快速查找,但不支持范围查询。
- 全文索引:适合搜索文本内容。
- 空间索引:适合地理数据。
- 前缀索引:适合长字段。
- 复合索引:适合多条件查询。
- 唯一索引:适合需要唯一性的字段。