在互联网大厂的一间明亮的面试室内,严肃的面试官坐在桌前,对面是紧张又怀揣期待的求职者王铁牛。面试开始,一场关于 Java 技术的考验拉开帷幕。
第一轮提问 面试官:首先问几个基础问题。Java 中的基本数据类型有哪些? 王铁牛:这个我知道,有 byte、short、int、long、float、double、char、boolean。 面试官:回答正确,很不错。那你说说 ArrayList 和 LinkedList 的区别是什么? 王铁牛:ArrayList 是基于数组实现的,它的随机访问速度快,但是插入和删除操作效率低;LinkedList 是基于链表实现的,插入和删除操作效率高,随机访问速度慢。 面试官:非常好,看来你基础掌握得很扎实。那 HashMap 的底层数据结构是什么? 王铁牛:HashMap 的底层是数组 + 链表 + 红黑树。当链表长度大于 8 且数组长度大于 64 时,链表会转化为红黑树,以提高查询效率。
第二轮提问 面试官:接下来深入一点。在多线程编程中,synchronized 和 Lock 有什么区别? 王铁牛:synchronized 是 Java 的关键字,是隐式锁,会自动释放锁;Lock 是一个接口,是显式锁,需要手动释放锁。 面试官:回答得不错。那你说说线程池的核心参数有哪些,分别代表什么含义? 王铁牛:线程池的核心参数有 corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory 和 handler。corePoolSize 是核心线程数,maximumPoolSize 是最大线程数,keepAliveTime 是线程空闲后的存活时间,unit 是时间单位,workQueue 是任务队列,threadFactory 是线程工厂,handler 是任务拒绝策略。 面试官:可以,理解得挺清晰。那 JVM 的内存模型是怎样的? 王铁牛:嗯……JVM 内存模型就是有堆、栈,还有方法区……具体的我有点记不太清了。
第三轮提问 面试官:再问几个框架相关的。Spring 的核心特性有哪些? 王铁牛:Spring 的核心特性有依赖注入和面向切面编程。依赖注入可以降低代码的耦合度,面向切面编程可以实现日志记录、事务管理等功能。 面试官:不错。那 Spring Boot 相对于 Spring 有什么优势? 王铁牛:Spring Boot 简化了 Spring 的配置,提供了很多默认配置,能够快速搭建项目,提高开发效率。 面试官:最后问一个,MyBatis 的工作原理是什么? 王铁牛:MyBatis 嘛……就是能和数据库交互,具体怎么工作的我有点说不明白。
面试官扶了扶眼镜,看着王铁牛说:“今天的面试就到这里,你回去等通知吧。我们后续会综合评估后给你反馈。”
问题答案详解
- Java 中的基本数据类型有哪些?
- Java 中有 8 种基本数据类型,分为 4 类:
- 整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节)。
- 浮点类型:float(4 字节)、double(8 字节)。
- 字符类型:char(2 字节)。
- 布尔类型:boolean(理论上 1 位,但在 Java 中通常占 1 字节)。
- Java 中有 8 种基本数据类型,分为 4 类:
- ArrayList 和 LinkedList 的区别是什么?
- 数据结构:ArrayList 基于动态数组实现,它在内存中是连续存储的;LinkedList 基于双向链表实现,每个节点包含数据和指向前一个节点和后一个节点的引用。
- 随机访问:ArrayList 可以通过索引直接访问元素,时间复杂度为 O(1);LinkedList 需要从头或尾开始遍历链表,时间复杂度为 O(n)。
- 插入和删除:ArrayList 在中间插入或删除元素时,需要移动后面的元素,时间复杂度为 O(n);LinkedList 只需要修改相邻节点的引用,时间复杂度为 O(1),但如果是在指定位置插入或删除,需要先遍历到该位置,时间复杂度为 O(n)。
- HashMap 的底层数据结构是什么?
- HashMap 的底层数据结构是数组 + 链表 + 红黑树。数组被称为哈希桶,每个桶存储一个链表或红黑树的头节点。当有新元素插入时,通过哈希函数计算元素的哈希值,根据哈希值确定元素在数组中的位置。如果该位置已经有元素,就将新元素插入到对应的链表或红黑树中。当链表长度大于 8 且数组长度大于 64 时,链表会转化为红黑树,以提高查询效率;当红黑树节点数小于 6 时,红黑树会退化为链表。
- 在多线程编程中,synchronized 和 Lock 有什么区别?
- 语法层面:synchronized 是 Java 的关键字,使用时可以修饰方法或代码块;Lock 是一个接口,需要通过实现类(如 ReentrantLock)来使用,使用时需要手动调用 lock() 和 unlock() 方法。
- 锁的获取和释放:synchronized 是隐式锁,当进入同步方法或代码块时自动获取锁,退出时自动释放锁;Lock 是显式锁,需要手动获取和释放锁,为了避免死锁,通常在 finally 块中释放锁。
- 锁的特性:synchronized 是非公平锁,不支持中断和超时;Lock 可以实现公平锁和非公平锁,支持中断和超时,还可以尝试获取锁。
- 线程池的核心参数有哪些,分别代表什么含义?
- corePoolSize:核心线程数,线程池创建后,默认情况下核心线程不会被销毁,会一直存活在线程池中等待任务。
- maximumPoolSize:最大线程数,线程池允许创建的最大线程数量。
- keepAliveTime:线程空闲后的存活时间,当线程池中的线程数量超过核心线程数时,多余的空闲线程在等待新任务的时间超过 keepAliveTime 后会被销毁。
- unit:keepAliveTime 的时间单位,如 TimeUnit.SECONDS 表示秒。
- workQueue:任务队列,用于存储提交的任务,常用的任务队列有 ArrayBlockingQueue、LinkedBlockingQueue 等。
- threadFactory:线程工厂,用于创建线程,可以自定义线程的名称、优先级等。
- handler:任务拒绝策略,当线程池中的线程数量达到最大线程数,且任务队列已满时,新提交的任务会被拒绝,这时会调用任务拒绝策略来处理。常用的任务拒绝策略有 AbortPolicy(直接抛出异常)、CallerRunsPolicy(由调用线程处理任务)等。
- JVM 的内存模型是怎样的?
- JVM 内存模型主要分为以下几个部分:
- 堆(Heap):是 JVM 中最大的一块内存区域,用于存储对象实例和数组。堆是所有线程共享的,垃圾回收主要就是针对堆进行的。
- 栈(Stack):包括虚拟机栈和本地方法栈。虚拟机栈为 Java 方法服务,每个方法在执行时会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息;本地方法栈为本地方法服务。
- 方法区(Method Area):用于存储类的信息、常量、静态变量等。在 JDK 1.8 之前,方法区也被称为永久代,JDK 1.8 及以后,方法区被元空间(Metaspace)取代,元空间使用的是本地内存。
- 程序计数器(Program Counter Register):是一块较小的内存区域,它可以看作是当前线程所执行的字节码的行号指示器,每个线程都有一个独立的程序计数器。
- JVM 内存模型主要分为以下几个部分:
- Spring 的核心特性有哪些?
- 依赖注入(Dependency Injection,DI):是一种设计模式,通过将对象的依赖关系从对象内部转移到外部,降低了代码的耦合度。Spring 容器负责创建对象并将依赖对象注入到需要的对象中。
- 面向切面编程(Aspect-Oriented Programming,AOP):是一种编程范式,它允许开发者在不修改原有代码的情况下,对程序进行增强。Spring AOP 可以实现日志记录、事务管理、权限验证等功能,通过定义切面、切点和通知来实现。
- Spring Boot 相对于 Spring 有什么优势?
- 简化配置:Spring Boot 提供了很多默认配置,通过自动配置机制,开发者可以快速搭建项目,减少了大量的 XML 配置文件。
- 快速开发:Spring Boot 内置了嵌入式服务器(如 Tomcat、Jetty 等),可以直接运行项目,无需部署到外部服务器。同时,它还提供了很多 Starter 依赖,方便开发者快速集成各种功能。
- 监控和管理:Spring Boot Actuator 提供了对应用程序的监控和管理功能,如查看应用程序的健康状态、内存使用情况等。
- MyBatis 的工作原理是什么?
- 加载配置文件:MyBatis 首先会加载配置文件(如 mybatis-config.xml 和映射文件),解析配置文件中的信息,包括数据库连接信息、SQL 映射信息等。
- 创建 SqlSessionFactory:根据配置文件创建 SqlSessionFactory,它是 MyBatis 的核心对象,用于创建 SqlSession。
- 创建 SqlSession:通过 SqlSessionFactory 创建 SqlSession,SqlSession 是 MyBatis 与数据库交互的会话对象,它提供了执行 SQL 语句的方法。
- 执行 SQL 语句:通过 SqlSession 执行 SQL 语句,MyBatis 会根据 SQL 映射信息将 SQL 语句发送到数据库执行,并将查询结果映射到 Java 对象中。
- 关闭 SqlSession:使用完 SqlSession 后,需要关闭它,释放资源。