新鲜出炉的Java 美团面试葵花宝典

1、什么是反射机制?

JAVA 反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

2、concurrenthashmap 的解析

ConcurrentHashMap 是 Java 中线程安全的 Map 实现, 它允许多个线程同时对 Map 进行读写操作,而不会导致数据不一致或者其他线程安全问题。 它的主要特点包括:

1. 分段锁设计: ConcurrentHashMap 将整个 Map 分为多个 segment, 每个 segment 都维护着一个独立的哈希表。 在读写时, 只需要锁定对应的 segment, 不需要锁定整个 Map, 从而提高了并发度。

2. 基于 CAS 操作的并发控制: ConcurrentHashMap 的 put()、 get()、 remove()等操作都是通过CAS( Compare and Swap) 实现的。 在 put()操作中, 如果两个线程同时插入了同一个 key, 只有一个线程的操作会成功, 另一个线程的操作会失败, 从而保证了数据的正确性。

3. 支持高并发读操作: ConcurrentHashMap 的读操作不需要锁定 Map, 多个线程可以同时对 Map进行读操作, 不会出现并发安全问题。

4. 空间动态调整: ConcurrentHashMap 支持动态扩容和收缩, 可以根据当前 Map 中的数据量自动调整容量。总之, ConcurrentHashMap 通过分段锁设计和基于 CAS 操作的并发控制等技术手段, 实现了高并发下的安全读写操作, 并且具有较好的扩展性和空间利用率。 但需要注意的是, ConcurrentHashMap并不保证 Map 中的数据是按照插入顺序或者其他顺序排列的, 因此不适合用于有序数据的存储和查询。

3、Hashmap 原理, 为什么要红黑树而不是二叉树

HashMap 是 Java 中常用的 Map 实现, 它基于哈希表实现, 可以快速地插入、 删除和查找数据。

HashMap 的主要原理如下:

1. 存储结构: HashMap 内部使用数组来存储键值对, 每个键值对对应数组中的一个元素。 当插入一个键值对时, 会根据 key 的哈希值计算出对应的数组下标, 然后将键值对存储在该位置。

2. 解决哈希冲突: 由于不同的 key 可能计算出相同的哈希值, 所以在插入过程中可能会出现哈希冲突。 HashMap 通过链表法解决哈希冲突, 即将冲突的键值对以链表的形式存储在同一数组位置上。 当查找一个键值对时, 会先根据 key 的哈希值计算出对应的数组下标, 然后遍历该位置上的链表, 直到找到对应的键值对或者遍历完整个链表。

3. 优化红黑树: 在 JDK1.8 中, 当某个数组位置上的链表长度超过了阈值(默认为 8) , HashMap会将链表转化为红黑树, 以提高查找效率。 红黑树相对于普通的二叉树, 具有平衡性更好、 查找时间更短等优点, 因此更适合用于高效的查找操作。

为什么要使用红黑树而不是二叉树呢?

主要是因为红黑树在插入和删除操作时, 能够自动平衡树的结构, 使得整棵树的高度保持在一个较小的范围内, 从而保证查找、 插入和删除操作的时间复杂度稳定在 O(logn)。 而二叉树没有自平衡的特性, 如果插入和删除操作不当, 可能会导致树的高度过高, 使得查找时间复杂度变为 O(n), 因此不适合用于高效的 Map 实现。

4、hashmap 底层原理

HashMap 是 Java 中最常用的 Map 实现之一, 它基于哈希表实现快速的插入、 查找和删除操作。

HashMap 的底层原理如下:

1. 存储结构: HashMap 内部使用一个数组来存储键值对, 每个键值对对应数组中的一个元素。 数组的大小一般是 2 的幂次方, 以便更好地利用哈希函数的性质。

2. 计算哈希值: 当插入一个键值对时, HashMap 会根据 key 的哈希值计算出对应的数组下标。 计算哈希值的过程可以由 key 的 hashCode()方法完成, 也可以使用自定义的哈希函数。

3. 解决哈希冲突: 由于不同的 key 可能计算出相同的哈希值, 所以在插入过程中可能会出现哈希冲突。 HashMap 通过链表法解决哈希冲突, 即将冲突的键值对以链表的形式存储在同一数组位置上。 当查找一个键值对时, 会先根据 key 的哈希值计算出对应的数组下标, 然后遍历该位置上的链表, 直到找到对应的键值对或者遍历完整个链表。

4. 扩容机制: 当 HashMap 的数组大小达到一定的阈值(默认为 75%) , 会触发扩容操作。 扩容的过程会重新计算每个键值对的哈希值, 然后将其存储在新的数组位置上。 扩容操作需要耗费一定的时间, 因此需要在初始化时预估 HashMap 中键值对的数量, 以便尽可能地减少扩容操作的次数。

5. 红黑树优化: 在 JDK1.8 中, 当某个数组位置上的链表长度超过了阈值(默认为 8) , HashMap会将链表转化为红黑树, 以提高查找效率。 红黑树相对于普通的二叉树, 具有平衡性更好、 查找时间更短等优点, 因此更适合用于高效的查找操作。总之, HashMap 通过哈希表和链表法解决哈希冲突, 以及扩容和红黑树优化等技术手段, 实现了高效的插入、 查找和删除操作, 并且具有较好的空间利用率和扩展性。 但需要注意的是, HashMap 并不保证 Map 中的数据是按照插入顺序或者其他顺序排列的, 因此不适合用于有序数据的存储和查询。

5、b tree 和 b+tree 解析

B 树和 B+树是常用的一种平衡搜索树, 它们的主要区别在于内部节点和叶子节点的存储方式和指

针结构不同, 从而导致它们在不同场景下具有不同的性能特点。

B 树是一种多路平衡查找树, 每个节点可以存储多个 key-value 键值对, 具有较好的磁盘 IO 性

能。 B 树通常被用于文件系统和数据库系统中, 可以高效地支持范围查找和随机访问等操作。

B+树是在 B 树的基础上进一步优化的一种平衡树, 其内部节点仅存储 key, 而真正的 value 均存储在叶子节点中。 这种设计使得 B+树具有更好的磁盘 IO 性能和更高的查询效率, 适用于需要频繁范围查询和顺序遍历的场景, 例如数据库索引。

B+树与 B 树相比, 具有更高的查询效率和更好的空间利用率。 因为 B+树只需要访问叶子节点才能查找到 value, 而 B 树需要遍历所有节点。 此外, B+树的内部节点仅存储 key, 可以存储更多的key, 从而提高了空间利用率。

6、mysql 索引

MySQL 索引是一种用于优化数据库查询性能的数据结构。 索引可以帮助数据库系统快速定位并检索数据, 从而提高查询效率。 MySQL 支持多种类型的索引, 包括 B-tree 索引、 哈希索引、 全文索引等。

B-tree 索引是 MySQL 最常用的索引类型, 也是默认的索引类型。 B-tree 索引是一种基于平衡树的索引结构, 它可以高效地支持范围查询和精确查找等操作。 B-tree 索引在查询过程中会从根节点开始依次遍历 B-tree, 直到找到对应的叶子节点。 如果需要范围查询, 则可以通过遍历 B-tree 的方式来找到对应的叶子节点区间。 B-tree 索引通常适用于单值查询和多值范围查询, 例如 WHEREid = 1 或 WHERE age BETWEEN 20 AND 30 等语句。

哈希索引是一种基于哈希表的索引结构, 它可以快速定位并检索数据。 哈希索引通常适用于精确查找, 例如 WHERE id = 1 或 WHERE name = 'John'等语句。 但是, 哈希索引不支持范围查询和排序等操作, 因为哈希表中的数据是无序的。全文索引是一种用于全文搜索的索引结构, 它可以高效地处理自然语言查询。 全文索引通常适用于对文本内容进行查询, 例如 WHERE MATCH(title, content) AGAINST ('MySQL' IN BOOLEANMODE)等语句。

7、Arraylist 和 linkedlist 的区别

ArrayList 和 LinkedList 是 Java 集合框架中两种常见的 List 实现, 它们的底层数据结构不同,

因此在一些操作上会有所差异。

1. 底层数据结构

ArrayList 底层采用数组实现, 因此支持随机访问, 可以通过下标索引访问元素, 时间复杂度为

O(1)。 但是在插入和删除操作时, 需要移动后面的元素, 时间复杂度为 O(n)。

LinkedList 底层采用双向链表实现, 因此插入和删除操作只需要改变相邻节点的指针, 时间复杂

度为 O(1), 但是随机访问需要遍历链表, 时间复杂度为 O(n)。

1. 空间占用

ArrayList 的内部是一个数组, 当元素个数不足数组容量时, 会浪费一部分内存空间。 而LinkedList 每个元素需要额外的空间来存储前后节点的指针, 因此会占用更多的内存空间。

1. 迭代器性能

在迭代操作时, ArrayList 使用普通迭代器或增强 for 循环的性能比 LinkedList 更优。 这是因为ArrayList 的数据存储在连续的内存中, 迭代时可以直接访问内存, 而 LinkedList 需要通过遍历链表来访问每个元素。

1. 使用场景

ArrayList 适用于随机访问较多, 插入和删除操作较少的场景, 例如缓存、 排序、 搜索等。 而LinkedList 适用于插入和删除操作较多, 随机访问较少的场景, 例如队列、 栈等。综上所述, 选择 ArrayList 还是 LinkedList 要根据实际场景需求来决定。

8、数据库事务 4 大特性

数据库事务是指一系列数据库操作组成的逻辑工作单元, 具有以下四个特性( 即 ACID 特性) :

1. 原子性( Atomicity) : 事务中的所有操作要么全部完成, 要么全部不完成, 不会只完成其中

的一部分操作。 如果一个操作失败, 整个事务将被回滚到事务开始前的状态, 所有的操作都将

被撤销。

2. 一致性( Consistency) : 事务执行前后, 数据库的状态必须保持一致。 如果事务执行后, 数

据库的状态不符合预期, 事务将被回滚到事务开始前的状态, 以保证数据库的一致性。

3. 隔离性( Isolation) : 事务执行的过程中, 对其他事务是隔离的。 即每个事务都认为自己是

唯一在操作数据库的事务, 不受其他事务的干扰。 事务隔离级别包括读未提交、 读已提交、 可

重复读和串行化, 不同的隔离级别会影响并发性能和数据的一致性。

4. 持久性(Durability) : 事务完成后, 对数据库的修改必须永久保存在数据库中, 即使出现了

系统故障或断电等情况, 也不能丢失。 为了实现持久性, 数据库通常使用日志来记录所有的事

务操作, 以便在系统故障恢复后恢复数据。

9、数据库隔离级别

数据库隔离级别是指多个事务之间相互隔离的程度, 通常包括四个级别:

1. 读未提交(Read Uncommitted) : 最低级别, 事务可以读取其他事务未提交的数据, 也就是脏读。 虽然可以提高并发性能, 但是会导致数据的不一致, 一般不建议使用。

2. 读已提交(Read Committed) : 事务只能读取其他事务已提交的数据, 避免了脏读, 但是可能会出现不可重复读和幻读的问题。

3. 可重复读(Repeatable Read) : 在同一个事务内, 多次读取同一个数据的结果都是一样的,不会出现不可重复读的问题。 但是可能会出现幻读的问题, 即在同一个事务内, 一个范围内的数据记录被其他事务修改或删除。

4. 串行化(Serializable) : 最高级别, 事务之间相互完全隔离, 每个事务都像是在独立的系统中执行, 避免了所有并发问题, 但是对系统性能影响较大。不同的隔离级别对并发性和数据一致性的影响不同, 需要根据实际情况选择适当的隔离级别。

10、MYSQL 支持的存储引擎有哪些, 有什么区别 ?

常见的存储有两个, InnoDB 和 MyISAM, 当然 mysql 还支持其他的存储引擎, 只是用的不多。

InnoDB 和 MyISAM 主要的区别是:

 InnoDB 支持事务, 而 MyISAM 不支持事务

 InnoDB 支持表锁和行锁, MyISAM 只支持表锁

 InnoDB 支持外键, MyISAM 不支持外键

解释下幻读

幻读是指在同一个事务内, 第一次查询某个范围内的数据时, 没有查询到某些行, 但是在该事务

内后续再次查询同一范围内的数据时, 却发现有新的数据行插入进来了, 就像是出现了幻觉一

样, 因此称之为“幻读”。

幻读与不可重复读的区别在于, 不可重复读是指在同一个事务内, 多次读取同一条数据的结果不

一样, 而幻读是指在同一个事务内, 多次读取同一个范围内的数据, 结果不一样。

幻读通常发生在读取范围内的数据时, 例如使用 SELECT...WHERE 语句进行范围查询, 如果在该范围内有新的数据行被插入或删除, 那么在同一个事务内再次执行相同的查询时, 就会出现幻读象。为了避免幻读问题, 可以使用更高的隔离级别, 如 Serializable(串行化) , 但是这会影响系统的并发性能, 因此需要根据实际情况进行权衡和选择。 另外, 可以使用行级锁或者使用乐观锁机制来避免幻读问题。

11、什么是聚簇索引什么是非聚簇索引 ?

聚簇索引和非聚簇索引是关系型数据库中常见的两种索引类型。

聚簇索引是将数据存储在同一个物理页面上的一种索引方式。 在聚簇索引中, 数据行的存储顺序

与索引的顺序是一致的, 因此可以加快数据的访问速度。 通常情况下, 表的主键会作为聚簇索引

的索引键。 因为主键是唯一的, 聚簇索引也能够保证数据的唯一性。

非聚簇索引则是将索引与数据分开存储的一种索引方式。 在非聚簇索引中, 索引保存着数据行的

指针或者地址, 而数据则是存储在另一个物理页面中的。 由于非聚簇索引中数据的存储顺序和索

引的顺序不一致, 因此需要多次磁盘访问才能够得到完整的数据, 导致查询效率相对较低。 但

是, 非聚簇索引具有更高的更新效率, 因为只需要更新索引页面就可以完成更新操作。

总的来说, 聚簇索引适合那些经常需要扫描整个表的查询操作, 而非聚簇索引则适合那些需要频

繁更新数据的操作。 在实际的应用中, 可以根据实际的业务需求和数据访问模式来选择不同的索

引方式。

评论区(附全套面试题+标准答案)

猜你喜欢

转载自blog.csdn.net/JACK_SUJAVA/article/details/130766476