?面试问题:
请解释String为什么被设计成不可变的,以及不可变性的优势是什么?
?在什么情况下你会使用Java的反射机制?能否提供一个实际应用的例子?
详细解释一下Java内存结构中的方法区是用来存储什么信息的?
当你在设计一个新的类时,你更倾向于使用接口还是抽象类?为什么?
请解释在实际项目中为什么需要使用方法的重写和重载?
你在实际项目中如何决定何时使用"==",何时使用equals方法?
请解释垃圾回收是如何工作的,以及在Java中手动触发垃圾回收的方法是什么?
为什么HashMap选择在链表长度过长时转换为红黑树而不是立即进行扩容?
请解释HashMap长度为2的N次方的设计对性能的影响。
在多线程环境中,你更愿意使用HashMap还是HashTable?为什么?
你能比较一下使用普通for循环和Java8的Stream API进行列表遍历的优缺点吗?
线程的生命周期?
你在实际项目中是如何应用设计模式的?能分享一个具体的例子吗?
你在项目中是如何预防缓存雪崩和缓存穿透的?能分享一些具体的实践经验吗?
请解释Redis哨兵集群的工作原理,并说明在项目中如何保障Redis高可用性。
在使用Redis和MySQL时,你是如何确保数据一致性的?能分享一些实际应用中的挑战和解决方案吗?
你在使用MyBatis动态SQL时是如何提高SQL灵活性和可维护性的?
在使用MyBatis时,你更倾向于使用ResultType还是ResultMap?为什么?
在使用MyBatisPlus时,你认为哪些注解是最常用的,为什么选择使用它们?
附属答案:
- String/StringBuffer/StringBuilder区别:String是不可变的字符串,每次修改都会创建新的对象,适用于不经常修改的字符串操作;StringBuffer是可变的字符串,线程安全,适用于多线程环境;StringBuilder也是可变的字符串,但不是线程安全的,适用于单线程频繁修改字符串的场景。
- 反射机制:Java的反射机制是指在运行时动态地获取类的信息并操作类或对象的能力。通过反射,我们可以在编译时无法确定的情况下,通过类名获取类的实例、获取类的字段、方法、构造函数等信息,并且可以在运行时调用这些方法或访问这些字段。
- JVM内存结构:Java的内存结构主要包括方法区、堆、虚拟机栈、本地方法栈和程序计数器。方法区用于存储类信息,堆用于存储对象实例,虚拟机栈用于存储方法调用和局部变量,本地方法栈用于存储非Java方法信息,程序计数器用于记录当前线程执行的指令地址。
- 接口和抽象类的区别:接口是一种规范,它定义了一组方法的签名,而不包含具体实现。一个类可以实现多个接口。抽象类是一种可以包含具体方法和抽象方法的类,它可以被继承,但不能被实例化。一个类只能继承一个抽象类。简而言之,接口关注的是行为的规范,而抽象类关注的是共享的功能。
- 重写(override)和重载(overload)的区别:重写(override)指的是子类重新实现了父类中已有的方法,子类的方法具有相同的名称、参数列表和返回类型。重载(overload)指的是在同一个类中定义了多个方法,它们具有相同的名称但参数列表不同。重写主要涉及继承和多态性,而重载则是在同一个类中的方法之间进行区分。简而言之,重写是对已有方法的重新实现,而重载是创建具有相同名称但不同参数的多个方法。
- ==与equals区别:"=="用于比较对象的引用或基本类型的值是否相等,而equals方法用于比较对象的内容是否相等。换句话说,"=="比较的是身份,equals比较的是内容。
- JVM的GC垃圾回收机制:GC垃圾回收机制是指Java虚拟机自动管理内存的机制,通过自动识别和回收不再使用的对象,释放对应的内存资源,以避免内存泄漏和提高程序性能。
- HashMap什么时候扩容:在JDK1.7中,当HashMap中元素数量超过当前容量与负载因子(默认为0.75)的乘积时,会触发扩容操作,扩容后的容量为当前容量的两倍。例如,初始容量为16,当元素数量达到12时会触发扩容,扩容后的容量为32------------在JDK1.8中,当HashMap中链表长度超过阈值(默认为8)时,会将链表转换为红黑树,而不是立即进行扩容,只有当红黑树节点数量超过容量与负载因子的乘积阈值时(默认为64),才会进行扩容,扩容后的容量为当前容量的两倍。因此,在JDK1.8中,扩容的条件是链表长度超过阈值并且红黑树节点数量超过容量与负载因子乘积阈值。
- HashMap的长度为什么是 2的 N 次方:
HashMap的长度为2的N次方是为了提高哈希表的性能,尤其是在计算哈希值映射到数组索引的时候。这涉及到HashMap内部使用的"取模运算"。
当HashMap的长度为2的N次方时,通过位运算(取模操作相当于对长度取余)可以用更高效的方式计算哈希值映射到数组索引的位置。具体说,对长度为2的N次方的数组进行取余操作,可以使用位运算(&
操作)替代普通的取余操作(%
操作),这样可以提高计算效率。
简单来说,长度为2的N次方的数组使得计算哈希值映射到数组索引的操作更加高效,减少了计算的复杂性。这是为了优化HashMap在处理大量数据时的性能。
- HashMap和HashTable区别:HashMap是非线程安全的、允许空键和空值,并使用数组+链表/红黑树底层实现;HashTable是线程安全的、不允许空键和空值,并使用数组+链表底层实现。
- 遍历LIST有哪些方式:普通遍历:for(int i=0; i< arrays.size(); i++)、增强for遍历:for(String str : arrays)、foreach遍历:list.forEach((str) -> xxxxx)、使用Iterator迭代器遍历j、ava8 stream遍历
- 线程的状态:线程的状态包括:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)、终止(Terminated)。
- Spring中的设计模式有哪些:工厂模式:?Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对 象-------单例模式:?Spring中的bean默认都是单例的---代理模式:?Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
-
数据库的ACID特性:ACID特性是指原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),用于保证数据库事务的可靠性和一致性。其中:原子性(Atomicity):事务中的操作要么全部成功,要么全部失败。事务是一个不可分割的单元,要么全部执行,要么全部回滚。如果事务中的任何操作失败,所有操作都将被回滚到事务开始之前的状态,以保证数据的一致性。一致性(Consistency):事务的执行应使数据库从一个一致性状态转移到另一个一致性状态。在事务开始和结束时,数据库的完整性约束应得到满足,确保数据的正确性和一致性。隔离性(Isolation):每个事务在执行过程中都应该与其他事务隔离。并发事务的执行应当互不干扰,每个事务应该感知不到其他事务的存在或并发执行。隔离级别定义了不同事务之间的可见性和互相影响的程度。持久性(Durability):一旦事务提交成功,其对数据库的修改应该永久保存,即使系统发生故障或重启,也应该能够保持数据的持久性。
-
Redis的缓存雪崩、缓存穿透、缓存击穿:
缓存穿透可以通过使用布隆过滤器来快速判断请求的Key是否合法,避免查询不存在的数据。
缓存击穿可以通过使用互斥锁来保护数据库查询,确保只有一个线程能够查询数据库并写入缓存,避免多个并发请求同时访问数据库。
缓存雪崩可以通过合理设置缓存的失效时间,使用热点数据预热来减少对缓存的依赖,从而避免整个缓存层的崩溃。
- Redis的哨兵集群(Redis Sentinel):Redis的哨兵集群主要用于实现高可用性,监控Redis主、从节点的状态变化,并在主节点失效时自动将从节点升级为主节点。哨兵集群由多个哨兵节点组成,工作原理是哨兵节点通过相互通信,监测主节点的健康状态,当主节点失效时,选举新的主节点,并通知其他从节点进行切换,确保系统的可用性。
- Redis(或ElasticSearch)和MySQL如何保持数据一致性:
Elasticsearch和MySQL的数据一致性可以通过以下三种方案实现:
1. 双写:每次写入操作同时将数据写入Elasticsearch和MySQL,确保数据一致性,但可能增加写延迟和复杂性。
2. 异步队列:将写入操作请求放入队列中,后台任务异步地将数据写入Elasticsearch和MySQL,提高写入性能,但可能导致一定的数据不一致性。
3. Canal方案:使用Canal工具订阅MySQL的binlog日志,实时将数据同步到Elasticsearch,实现数据的实时增量同步,但需要额外的工具和配置。
- MyBatis动态SQL:
MyBatis 动态 SQL 可以让我们在 XML 映射文件内,以标签的形式编写动态 SQL,完成逻辑判断和动态拼接 SQL 的功能;
MyBatis 提供了 9 种动态 SQL 标签:trim、where、set、foreach、if、choose、when、otherwise、bind;
执行原理:使用 OGNL 从 SQL 参数对象中计算表达式的值,根据表达式的值动态拼接 SQL,以此来完成动态 SQL 的功能。
- ResultType 和 ResultMap 的区别:如果数据库结果集中的列名和要封装实体的属性名完全一致的话用 resultType 属性--------如果数据库结果集中的列名和要封装实体的属性名有不一致的情况用 resultMap 属 性,通过 resultMap 手动建立对象关系映射,resultMap 要配置一下表和类的一一对应关系,所以说就算你的字段名和你的实体类的属性名不一样也没关系,都会给你映射出来
- MyBatisPlus的常用注解:@TableName:用于指定实体类对应的数据库表名。该注解可以在实体类上添加,表示该类映射到指定的数据库表。例如:@TableName("user")。@TableField:用于指定实体类的字段对应的数据库表的字段名。该注解可以在实体类的字段上添加,表示该字段映射到指定的数据库表字段。例如:@TableField("name")。@TableId:用于指定实体类的字段作为数据库表的主键。该注解可以在实体类的字段上添加,表示该字段作为数据库表的主键。例如:@TableId(value = "id", type = IdType.AUTO)。@Version:用于指定实体类的字段作为乐观锁的版本字段。乐观锁是一种并发控制机制,通过版本号的变化来判断数据是否被修改。该注解可以在实体类的字段上添加,表示该字段作为乐观锁的版本字段。例如:@Version。
好的,这是一个基本面试题集合,涵盖了必须要掌握的基础知识。