《互联网大厂面试:Java 核心、并发、框架与中间件知识大考验》

47 阅读7分钟

互联网大厂面试:Java 核心、并发、框架与中间件知识大考验

在互联网大厂的一间安静面试室内,严肃的面试官正对面坐着略显紧张的求职者王铁牛。面试即将开始,一场关于 Java 技术知识的考验拉开帷幕。

第一轮提问 面试官:“我们先从 Java 核心知识开始。Java 中基本数据类型有哪些,它们分别占多少字节?” 王铁牛:“基本数据类型有 byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节)、float(4 字节)、double(8 字节)、char(2 字节)、boolean(虽然规范没明确大小,但一般认为 1 位)。” 面试官:“回答得不错。那在 Java 里,== 和 equals 方法有什么区别?” 王铁牛:“== 对于基本数据类型比较的是值,对于引用数据类型比较的是引用地址;equals 方法如果没有重写,和 == 一样比较引用地址,像 String 类重写了 equals 方法,就比较的是字符串内容。” 面试官:“很好。那说说 Java 中的继承和多态是怎么回事?” 王铁牛:“继承是指一个类可以继承另一个类的属性和方法,被继承的类叫父类,继承的类叫子类。多态是指同一个行为具有多个不同表现形式或形态的能力,通过继承和接口实现,比如父类引用指向子类对象。” 面试官:“回答得很清晰,基础很扎实。”

第二轮提问 面试官:“接下来我们聊聊 JUC 和多线程。线程有哪些状态?” 王铁牛:“线程有新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)、终止(Terminated)这些状态。” 面试官:“不错。那说说 synchronized 和 ReentrantLock 的区别。” 王铁牛:“synchronized 是 Java 关键字,是隐式锁,会自动释放;ReentrantLock 是类,是显式锁,需要手动释放。ReentrantLock 功能更强大,比如可以实现公平锁,还能中断等待锁的线程。” 面试官:“有一定理解。那线程池有哪些常用的创建方式?” 王铁牛:“可以通过 Executors 工具类创建,像 newFixedThreadPool(创建固定大小的线程池)、newCachedThreadPool(创建可缓存的线程池)、newSingleThreadExecutor(创建单线程的线程池),不过阿里巴巴开发手册不建议用 Executors 创建,推荐用 ThreadPoolExecutor 手动创建。” 面试官:“回答得还行,对线程池的创建方式有比较全面的认识。”

第三轮提问 面试官:“现在考察一下框架相关知识。Spring 中的 IOC 和 AOP 是什么?” 王铁牛:“IOC 是控制反转,把对象的创建和依赖关系的管理交给 Spring 容器,降低了代码的耦合度;AOP 是面向切面编程,在不修改原有代码的基础上,对程序进行增强,比如实现日志记录、事务管理等功能。” 面试官:“回答得不错。那 Spring Boot 相对于 Spring 有什么优势?” 王铁牛:“Spring Boot 简化了 Spring 应用的开发,它有自动配置功能,能快速搭建项目,内置了服务器,像 Tomcat,还提供了很多 Starter 依赖,方便集成各种功能。” 面试官:“理解得可以。那 MyBatis 中 #{} 和 {} 的区别是什么?” **王铁牛**:“#{} 是预编译处理,会把参数设置到占位符中,能防止 SQL 注入;{} 是直接替换,可能会有 SQL 注入风险。” 面试官:“整体回答得还可以。不过在一些细节的理解和应用场景上,还可以再深入。你先回家等通知吧,后续如果有进一步消息,我们会及时联系你。”

答案详解

  1. Java 基本数据类型及字节数
    • byte:1 字节,取值范围 -128 到 127。
    • short:2 字节,取值范围 -32768 到 32767。
    • int:4 字节,取值范围 -2147483648 到 2147483647。
    • long:8 字节,取值范围非常大,使用时需要在数字后面加 L。
    • float:4 字节,单精度浮点数,使用时需要在数字后面加 f。
    • double:8 字节,双精度浮点数。
    • char:2 字节,用于表示单个字符,采用 Unicode 编码。
    • boolean:虽然规范没明确大小,但一般认为 1 位,取值为 true 或 false。
  2. == 和 equals 方法的区别
    • == 是比较运算符,对于基本数据类型,比较的是它们的值是否相等;对于引用数据类型,比较的是它们在内存中的引用地址是否相同。
    • equals 方法是 Object 类的方法,默认情况下和 == 一样比较引用地址。但很多类(如 String、Integer 等)重写了 equals 方法,用来比较对象的内容是否相等。
  3. Java 中的继承和多态
    • 继承:是面向对象编程的一个重要特性,它允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码的复用和扩展。子类可以拥有父类的非私有属性和方法,还可以添加自己的属性和方法。
    • 多态:是指同一个行为具有多个不同表现形式或形态的能力。实现多态的方式主要有两种:继承和接口。通过父类引用指向子类对象,在运行时根据实际对象的类型调用相应的方法,实现了方法的动态绑定。
  4. 线程的状态
    • 新建(New):线程对象被创建,但还没有调用 start 方法。
    • 就绪(Runnable):线程调用了 start 方法,进入可运行状态,等待获取 CPU 时间片。
    • 运行(Running):线程获取了 CPU 时间片,正在执行任务。
    • 阻塞(Blocked):线程在等待获取一个排他锁,而该锁被其他线程持有。
    • 等待(Waiting):线程调用了 Object.wait()、Thread.join() 等方法,进入等待状态,需要其他线程唤醒。
    • 超时等待(Timed Waiting):线程调用了 Thread.sleep(long)、Object.wait(long) 等方法,在指定的时间内等待。
    • 终止(Terminated):线程执行完任务或因异常退出。
  5. synchronized 和 ReentrantLock 的区别
    • synchronized 是 Java 关键字,是隐式锁,由 JVM 自动获取和释放锁。它可以修饰方法和代码块,使用起来比较简单。
    • ReentrantLock 是 java.util.concurrent.locks 包下的类,是显式锁,需要手动调用 lock() 方法获取锁,unlock() 方法释放锁。它提供了更多的功能,如可中断锁、公平锁等。
  6. 线程池的常用创建方式
    • Executors.newFixedThreadPool(int nThreads):创建一个固定大小的线程池,线程数量固定,当有新任务提交时,如果线程池中有空闲线程,则执行任务;如果没有空闲线程,则任务会被放入队列等待。
    • Executors.newCachedThreadPool():创建一个可缓存的线程池,线程数量不固定,当有新任务提交时,如果线程池中有空闲线程,则执行任务;如果没有空闲线程,则创建新线程执行任务。当线程空闲一段时间后,会被回收。
    • Executors.newSingleThreadExecutor():创建一个单线程的线程池,只有一个线程执行任务,任务会按照提交的顺序依次执行。
    • ThreadPoolExecutor:手动创建线程池,可以更灵活地配置线程池的参数,如核心线程数、最大线程数、线程空闲时间、任务队列等。
  7. Spring 中的 IOC 和 AOP
    • IOC(控制反转):是一种设计思想,将对象的创建和依赖关系的管理从代码中转移到 Spring 容器中。Spring 容器负责创建对象、注入依赖,降低了代码的耦合度,提高了代码的可维护性和可测试性。
    • AOP(面向切面编程):是一种编程范式,它允许在不修改原有代码的基础上,对程序进行增强。AOP 通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,以切面的形式进行统一处理,提高了代码的复用性和可维护性。
  8. Spring Boot 相对于 Spring 的优势
    • 自动配置:Spring Boot 提供了大量的自动配置类,根据项目中引入的依赖自动配置 Spring 应用,减少了繁琐的配置文件。
    • 快速搭建:通过 Spring Initializr 或 Spring Boot CLI 可以快速创建项目骨架,节省了项目搭建的时间。
    • 内置服务器:Spring Boot 内置了 Tomcat、Jetty 等服务器,无需额外配置服务器,直接运行项目即可。
    • Starter 依赖:Spring Boot 提供了很多 Starter 依赖,方便集成各种功能,如 Spring Data JPA、Spring Security 等。
  9. MyBatis 中 #{} 和 ${} 的区别
    • #{} 是预编译处理,MyBatis 会将 #{} 替换为占位符?,然后使用 PreparedStatement 进行参数设置,能有效防止 SQL 注入。
    • 是直接替换,MyBatis会将{} 是直接替换,MyBatis 会将 {} 直接替换为参数的值,可能会存在 SQL 注入风险。一般在需要动态传入表名、列名等场景下使用 ${}。