《互联网大厂 Java 面试:核心知识、框架与中间件的全方位考察》

54 阅读3分钟

《互联网大厂 Java 面试:核心知识、框架与中间件的全方位考察》

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

第一轮面试开始

  • 面试官:首先,我们来聊聊 Java 核心知识。Java 中基本数据类型有哪些,它们的包装类又是什么?
  • 王铁牛:基本数据类型有 byte、short、int、long、float、double、char、boolean。对应的包装类分别是 Byte、Short、Integer、Long、Float、Double、Character、Boolean。
  • 面试官:回答得不错。那说说 Java 中多态的实现方式有哪些?
  • 王铁牛:多态的实现方式主要有方法重载和方法重写。方法重载是在同一个类中,方法名相同但参数列表不同;方法重写是子类重写父类的方法。
  • 面试官:很好。那在 Java 里,接口和抽象类有什么区别?
  • 王铁牛:接口里的方法默认是抽象的,不能有方法体,而抽象类里可以有抽象方法也可以有非抽象方法。一个类可以实现多个接口,但只能继承一个抽象类。

第二轮面试开始

  • 面试官:接下来我们谈谈 JUC 和多线程相关的。JUC 包下的 CountDownLatch 是用来做什么的,能举个业务场景例子吗?
  • 王铁牛:嗯……这个好像是和线程同步有关的吧,业务场景……我想想,好像和并发访问有点关系,具体我有点记不清了。
  • 面试官:那说说线程池的作用和常见的创建方式。
  • 王铁牛:线程池可以减少线程创建和销毁的开销。创建方式嘛,好像有通过 Executors 工具类创建,还有自己配置参数创建。不过具体的参数我不太清楚了。
  • 面试官:在多线程环境下,HashMap 会有什么问题?
  • 王铁牛:好像会有线程安全问题,具体怎么回事我也说不太明白。

第三轮面试开始

  • 面试官:现在说说框架相关的。Spring 的 IOC 和 AOP 是什么,能简单解释一下吗?
  • 王铁牛:IOC 好像是控制反转,就是把对象的创建和管理交给 Spring 容器。AOP 是面向切面编程,能在不修改原有代码的情况下增加功能。
  • 面试官:Spring Boot 相比 Spring 有什么优势?
  • 王铁牛:Spring Boot 好像更简单,能快速搭建项目,有很多默认配置。具体的优势我也说不太全。
  • 面试官:MyBatis 中 #{} 和 ${} 的区别是什么?
  • 王铁牛:这个……我记得好像一个是预编译,一个不是,具体哪个是哪个我搞混了。

面试接近尾声,面试官放下手中的笔,表情严肃地说:“今天的面试就到这里,你的基础知识有一定的掌握,但在一些比较深入的技术点上还有所欠缺。我们需要综合评估一下,你先回家等通知吧。”

问题答案详解

  1. Java 中基本数据类型有哪些,它们的包装类又是什么?
    • Java 中的基本数据类型分为四大类:整数类型(byte、short、int、long)、浮点类型(float、double)、字符类型(char)、布尔类型(boolean)。
    • 包装类是为了让基本数据类型具备对象的特性,方便在集合等场景中使用。对应的包装类分别是 Byte、Short、Integer、Long、Float、Double、Character、Boolean。例如,在使用集合存储整数时,不能直接存储 int 类型,需要使用 Integer 包装类。
  2. Java 中多态的实现方式有哪些?
    • 方法重载:在同一个类中,方法名相同但参数列表不同(参数的类型、个数、顺序不同)。方法重载主要是为了提供更方便的调用方式,例如在一个工具类中,可以有多个不同参数的 add 方法,分别用于不同类型数据的相加。
    • 方法重写:子类重写父类的方法,要求方法名、参数列表和返回值类型都相同(返回值类型可以是父类返回值类型的子类)。方法重写体现了子类对父类方法的扩展和修改,例如在图形类中,父类有一个计算面积的方法,子类可以根据自身的特点重写该方法。
  3. 在 Java 里,接口和抽象类有什么区别?
    • 方法实现:接口中的方法默认是抽象的,不能有方法体(Java 8 之后接口可以有默认方法和静态方法);抽象类中可以有抽象方法,也可以有非抽象方法。
    • 继承和实现:一个类可以实现多个接口,但只能继承一个抽象类。这使得接口更适合定义一组行为规范,而抽象类更适合作为一个类层次结构的基类。
    • 构造方法:接口没有构造方法,抽象类有构造方法,但不能实例化。
  4. JUC 包下的 CountDownLatch 是用来做什么的,能举个业务场景例子吗?
    • CountDownLatch 是一个同步工具类,它允许一个或多个线程等待其他线程完成操作。它通过一个计数器来实现,初始化时设置计数器的值,当一个线程完成任务后,计数器减 1,当计数器的值为 0 时,等待的线程可以继续执行。
    • 业务场景例子:在一个电商系统中,有多个服务需要初始化,如商品服务、订单服务、用户服务等。主线程需要等待所有服务初始化完成后才能对外提供服务。可以使用 CountDownLatch 来实现,主线程在启动各个服务线程后,调用 CountDownLatch 的 await 方法等待,每个服务线程初始化完成后调用 CountDownLatch 的 countDown 方法,当所有服务线程都完成初始化后,计数器为 0,主线程继续执行。
  5. 说说线程池的作用和常见的创建方式。
    • 作用:线程池可以减少线程创建和销毁的开销,提高系统的性能和稳定性。它可以对线程进行统一的管理和调度,避免创建过多的线程导致系统资源耗尽。
    • 常见创建方式
      • 通过 Executors 工具类创建:例如 Executors.newFixedThreadPool(int nThreads) 创建一个固定大小的线程池,Executors.newCachedThreadPool() 创建一个可缓存的线程池,Executors.newSingleThreadExecutor() 创建一个单线程的线程池。
      • 自定义线程池:通过 ThreadPoolExecutor 类来创建,可以根据业务需求灵活配置线程池的核心线程数、最大线程数、线程空闲时间等参数。例如:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5, // 核心线程数
    10, // 最大线程数
    60, // 线程空闲时间
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100) // 任务队列
);
  1. 在多线程环境下,HashMap 会有什么问题?
    • 线程不安全:HashMap 不是线程安全的,在多线程环境下,多个线程同时对 HashMap 进行读写操作可能会导致数据不一致的问题,例如出现死循环、数据丢失等情况。
    • 解决方案:可以使用线程安全的 Map 实现,如 Hashtable、ConcurrentHashMap。Hashtable 是线程安全的,但它的性能较低,因为它对所有的方法都进行了同步。ConcurrentHashMap 是一种高效的线程安全的 Map 实现,它采用了分段锁或 CAS 等技术来提高并发性能。
  2. Spring 的 IOC 和 AOP 是什么,能简单解释一下吗?
    • IOC(控制反转):是一种设计思想,将对象的创建和管理交给 Spring 容器,而不是由对象自己来创建和管理依赖对象。通过 IOC,降低了对象之间的耦合度,提高了代码的可维护性和可测试性。例如,在一个业务系统中,一个服务类需要依赖一个数据访问类,通过 Spring 的 IOC 容器,可以将数据访问类的实例注入到服务类中,而不需要在服务类中手动创建数据访问类的实例。
    • AOP(面向切面编程):是一种编程范式,它允许在不修改原有代码的情况下,对程序的某些特定部分进行增强。AOP 通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高了代码的复用性和可维护性。例如,在一个 Web 应用中,可以使用 AOP 来实现统一的日志记录,在方法执行前后插入日志记录的代码。
  3. Spring Boot 相比 Spring 有什么优势?
    • 快速搭建项目:Spring Boot 提供了很多默认配置和启动器,通过简单的配置和依赖引入,就可以快速搭建一个 Spring 项目,减少了繁琐的配置工作。
    • 内嵌服务器:Spring Boot 内嵌了 Tomcat、Jetty 等服务器,不需要额外部署服务器,直接可以将项目打包成可执行的 JAR 文件运行。
    • 自动配置:Spring Boot 会根据项目的依赖自动进行配置,减少了手动配置的工作量。例如,如果项目中引入了 Spring Data JPA 的依赖,Spring Boot 会自动配置数据源和 JPA 相关的配置。
    • 监控和管理:Spring Boot 提供了丰富的监控和管理功能,如健康检查、性能监控等,方便对项目进行运维和管理。
  4. MyBatis 中 #{} 和 ${} 的区别是什么?
    • #{}:是预编译处理,MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为占位符 ?,然后使用 PreparedStatement 来执行 SQL 语句。这样可以防止 SQL 注入攻击,提高了 SQL 语句的安全性。
    • **:是字符串替换,MyBatis在处理{}**:是字符串替换,MyBatis 在处理 {} 时,会直接将 中的内容替换到SQL语句中。例如,如果{} 中的内容替换到 SQL 语句中。例如,如果 {} 中是一个表名,MyBatis 会直接将表名替换到 SQL 语句中。由于 是直接替换,可能会导致SQL注入攻击,因此在使用时需要谨慎。通常,{} 是直接替换,可能会导致 SQL 注入攻击,因此在使用时需要谨慎。通常,{} 用于动态传入表名、列名等情况。例如:
<select id="getUserList" parameterType="String" resultType="User">
    SELECT * FROM ${tableName} WHERE username = #{username}
</select>

在这个例子中,${tableName} 会直接替换为传入的表名,而 #{username} 会作为占位符处理。