互联网大厂 Java 面试:核心知识、框架与中间件大考验
王铁牛怀揣着忐忑又期待的心情,走进了这家互联网大厂的面试间。严肃的面试官早已坐在那里,一场关于 Java 知识的严峻考验即将拉开帷幕。
第一轮提问 面试官:我们先从 Java 核心知识开始。Java 中基本数据类型有哪些? 王铁牛:这个我知道,有 byte、short、int、long、float、double、char、boolean。 面试官:回答得不错。那说说面向对象的四大特性是什么? 王铁牛:是封装、继承、多态和抽象。 面试官:很好。那 String、StringBuilder 和 StringBuffer 有什么区别? 王铁牛:String 是不可变的,每次对 String 的操作都会生成新的对象。StringBuilder 是非线程安全的,性能较高,而 StringBuffer 是线程安全的,性能相对低一些,因为它的方法加了同步锁。 面试官:非常棒,基础很扎实。
第二轮提问 面试官:接下来聊聊 JUC 和多线程。什么是线程池?为什么要使用线程池? 王铁牛:线程池就是预先创建好一定数量的线程,当有任务提交时,从线程池中获取线程来执行任务。使用线程池可以减少线程创建和销毁的开销,提高系统的性能和稳定性。 面试官:不错。那线程池有哪些常用的创建方式? 王铁牛:可以通过 Executors 工具类创建,比如 newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor 等。 面试官:那你说说这些创建方式各自的特点。 王铁牛:newFixedThreadPool 会创建固定大小的线程池,当有新任务提交时,如果线程池中有空闲线程就执行,没有就放入队列等待。newCachedThreadPool 是可缓存的线程池,会根据任务数量动态创建和销毁线程。newSingleThreadExecutor 是单线程的线程池,保证任务按顺序执行。 面试官:回答得很清晰,对线程池有一定的理解。
第三轮提问 面试官:现在说说框架相关的。Spring 的核心特性有哪些? 王铁牛:Spring 的核心特性有 IoC(控制反转)和 AOP(面向切面编程)。IoC 是把对象的创建和依赖关系的管理交给 Spring 容器,AOP 是在不修改原有代码的基础上增加额外的功能。 面试官:那 Spring Boot 相比 Spring 有什么优势? 王铁牛:Spring Boot 简化了 Spring 项目的配置,它有自动配置功能,能快速搭建项目,还内置了服务器,比如 Tomcat 等。 面试官:MyBatis 中 #{} 和 {} 的区别是什么? **王铁牛**:这个……嗯……好像 #{} 是预编译的,能防止 SQL 注入,{} 是直接替换,可能存在 SQL 注入风险,但是具体的使用场景我有点不太确定。 面试官:虽然回答不太完整,但大致方向是对的。Dubbo 是什么?它的核心组件有哪些? 王铁牛:Dubbo 是一个分布式服务框架。核心组件嘛……我记得有注册中心、远程调用、集群容错,具体的细节我有点模糊了。 面试官:看来你对框架有一定的了解,但有些细节还需要加强。
面试接近尾声,面试官看着王铁牛,严肃地说:“今天的面试就到这里了,你回家等通知吧。通过这次面试,能看出你对 Java 基础知识掌握得还不错,像 Java 核心知识和线程池相关的内容回答得很准确,这是你的优势。但在一些框架和中间件的细节方面,比如 MyBatis 和 Dubbo 的具体使用和原理,你还有所欠缺。我们后续会综合评估你的表现,有结果会及时通知你。”
问题答案详细解析
-
Java 中基本数据类型有哪些? Java 中有 8 种基本数据类型,可分为 4 类:
- 整数类型:
- byte:占 1 个字节,取值范围 -128 到 127。
- short:占 2 个字节,取值范围 -32768 到 32767。
- int:占 4 个字节,取值范围 -2147483648 到 2147483647。
- long:占 8 个字节,取值范围 -9223372036854775808 到 9223372036854775807,定义 long 类型变量时需要在数字后面加 L 或 l。
- 浮点类型:
- float:占 4 个字节,单精度浮点数,定义 float 类型变量时需要在数字后面加 F 或 f。
- double:占 8 个字节,双精度浮点数,是浮点数的默认类型。
- 字符类型:
- char:占 2 个字节,用于表示单个字符,使用单引号括起来,如 'A'。
- 布尔类型:
- boolean:只有两个值,true 和 false,占 1 位。
- 整数类型:
-
面向对象的四大特性是什么?
- 封装:将数据和操作数据的方法绑定在一起,隐藏对象的内部实现细节,只对外提供必要的接口。这样可以提高代码的安全性和可维护性,例如 Java 中的类和访问修饰符(private、protected、public)就是封装的体现。
- 继承:允许一个类继承另一个类的属性和方法,被继承的类称为父类(基类),继承的类称为子类(派生类)。继承可以实现代码的复用,提高开发效率。Java 中使用 extends 关键字实现继承,一个子类只能继承一个父类(单继承)。
- 多态:指同一个方法可以根据调用对象的不同而表现出不同的行为。多态的实现方式有两种:方法重载和方法重写。方法重载是指在同一个类中,多个方法具有相同的名称,但参数列表不同;方法重写是指子类重写父类的方法,方法名、参数列表和返回值类型都相同,但方法体不同。
- 抽象:抽象是指将一类对象的共同特征总结出来,形成抽象类或接口。抽象类不能实例化,只能被继承;接口是一种特殊的抽象类,接口中的方法都是抽象方法。抽象可以提高代码的可扩展性和可维护性。
-
String、StringBuilder 和 StringBuffer 有什么区别?
- 可变性:
- String 类是不可变的,它的内部使用一个 final 修饰的字符数组来存储字符串,一旦创建,其值不能被修改。如果对 String 进行修改操作,实际上是创建了一个新的 String 对象。
- StringBuilder 和 StringBuffer 是可变的,它们内部使用一个动态的字符数组来存储字符串,可以通过 append、insert 等方法对字符串进行修改,不会创建新的对象。
- 线程安全性:
- String 是不可变的,所以是线程安全的。
- StringBuffer 的方法都使用了 synchronized 关键字进行同步,所以是线程安全的,但由于同步会带来一定的性能开销,所以性能相对较低。
- StringBuilder 没有使用同步机制,所以是非线程安全的,但性能较高。
- 使用场景:
- 如果字符串很少进行修改操作,建议使用 String。
- 如果字符串需要频繁修改,且是在单线程环境下,建议使用 StringBuilder。
- 如果字符串需要频繁修改,且是在多线程环境下,建议使用 StringBuffer。
- 可变性:
-
什么是线程池?为什么要使用线程池?
- 线程池的定义:线程池是一种线程使用模式,它预先创建一定数量的线程,当有任务提交时,从线程池中获取线程来执行任务,任务执行完毕后线程不会销毁,而是返回线程池等待下一个任务。
- 使用线程池的原因:
- 减少线程创建和销毁的开销:线程的创建和销毁需要消耗系统资源和时间,使用线程池可以避免频繁创建和销毁线程,提高系统的性能。
- 提高响应速度:当有任务提交时,线程池中可能已经有空闲线程,任务可以立即执行,无需等待线程的创建。
- 便于线程管理:线程池可以控制线程的数量,避免创建过多的线程导致系统资源耗尽。同时,线程池还可以对线程进行监控和管理。
-
线程池有哪些常用的创建方式?各自的特点是什么?
- 通过 Executors 工具类创建:
- newFixedThreadPool:创建一个固定大小的线程池,线程池中的线程数量是固定的,当有新任务提交时,如果线程池中有空闲线程就执行,没有就放入队列等待。适用于需要控制并发线程数量的场景。
- newCachedThreadPool:创建一个可缓存的线程池,线程池中的线程数量是动态的,根据任务数量自动创建和销毁线程。如果线程池中有空闲线程且空闲时间超过 60 秒,线程会被销毁。适用于执行大量短期异步任务的场景。
- newSingleThreadExecutor:创建一个单线程的线程池,线程池中只有一个线程,保证任务按顺序执行。适用于需要保证任务顺序执行的场景。
- newScheduledThreadPool:创建一个可定时执行任务的线程池,可以定时或周期性地执行任务。适用于需要定时执行任务的场景。
- 通过 Executors 工具类创建:
-
Spring 的核心特性有哪些?
- IoC(控制反转):也称为依赖注入(DI),是指将对象的创建和依赖关系的管理交给 Spring 容器,而不是由对象自己来创建和管理依赖。通过 IoC,对象之间的耦合度降低,代码的可维护性和可测试性提高。Spring 容器通过 XML 配置文件、注解等方式来管理对象的创建和依赖关系。
- AOP(面向切面编程):是一种编程范式,它允许在不修改原有代码的基础上,对程序的某些特定部分进行增强。AOP 主要用于处理一些与业务逻辑无关的横切关注点,如日志记录、事务管理、权限验证等。Spring AOP 基于代理模式实现,有两种代理方式:JDK 动态代理和 CGLIB 代理。
-
Spring Boot 相比 Spring 有什么优势?
- 简化配置:Spring Boot 提供了自动配置功能,它会根据项目中引入的依赖自动配置 Spring 应用的各种组件,减少了大量的 XML 配置文件和 Java 配置类,使开发人员可以更专注于业务逻辑的实现。
- 快速搭建项目:Spring Boot 提供了 Spring Initializr 工具,可以快速生成项目骨架,包含了项目所需的依赖和基本配置,开发人员可以立即开始编写代码。
- 内置服务器:Spring Boot 内置了 Tomcat、Jetty 等服务器,开发人员可以直接运行 Spring Boot 应用,无需手动部署到服务器上。
- 监控和管理:Spring Boot Actuator 提供了丰富的监控和管理功能,如健康检查、性能监控、日志管理等,方便开发人员对应用进行监控和维护。
-
MyBatis 中 #{} 和 ${} 的区别是什么?
- 语法和处理方式:
- #{} 是预编译处理,MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为占位符 ?,然后使用 PreparedStatement 进行预编译,防止 SQL 注入。
- {} 时,会将 ${} 直接替换为变量的值,不会进行预编译,可能存在 SQL 注入风险。
- 使用场景:
- #{} 适用于传入参数作为查询条件的场景,如 WHERE name = #{name}。
- {tableName}。
- 语法和处理方式:
-
Dubbo 是什么?它的核心组件有哪些?
- Dubbo 的定义:Dubbo 是阿里巴巴开源的一个高性能、轻量级的分布式服务框架,用于实现服务的远程调用和服务治理。它可以帮助开发人员构建分布式系统,提高系统的可扩展性和可维护性。
- Dubbo 的核心组件:
- 服务提供者(Provider):暴露服务的一方,将自己的服务注册到注册中心。
- 服务消费者(Consumer):调用服务的一方,从注册中心获取服务提供者的地址信息,然后远程调用服务。
- 注册中心(Registry):负责服务的注册和发现,服务提供者将自己的服务信息注册到注册中心,服务消费者从注册中心获取服务提供者的地址信息。常用的注册中心有 ZooKeeper、Redis 等。
- 监控中心(Monitor):负责统计服务的调用次数、调用时间等信息,为服务的性能优化提供依据。
- 远程调用(RPC):实现服务的远程调用,Dubbo 支持多种远程调用协议,如 Dubbo 协议、HTTP 协议等。
- 集群容错(Cluster):当服务提供者出现故障时,Dubbo 提供了多种集群容错策略,如失败重试、快速失败等,保证服务的高可用性。