《互联网大厂面试:Java核心知识、JUC、JVM等技术大考验》

50 阅读12分钟

互联网大厂面试:Java核心知识、JUC、JVM等技术大考验

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

第一轮提问 面试官:首先问几个基础的 Java 核心知识问题。Java 中基本数据类型有哪些? 王铁牛:嗯,有 byte、short、int、long、float、double、char、boolean。 面试官:回答得不错。那 Java 的访问修饰符有哪些,它们的作用范围是怎样的? 王铁牛:访问修饰符有 public、protected、default(默认,不写修饰符时)、private。public 可以被所有类访问,protected 可以被同一包内的类以及不同包的子类访问,default 只能被同一包内的类访问,private 只能在本类中访问。 面试官:很好,看来基础掌握得挺扎实。那说说 Java 中多态的实现方式有哪些? 王铁牛:多态的实现方式主要有两种,一种是方法重载,就是在一个类中可以有多个方法名相同但参数列表不同的方法;另一种是方法重写,子类重写父类的方法,然后通过父类引用指向子类对象来实现多态。 面试官:非常棒,这一轮表现得很好。

第二轮提问 面试官:接下来进入 JUC 和多线程相关的问题。什么是 JUC,它包含哪些主要的组件? 王铁牛:JUC 就是 java.util.concurrent 包,里面有很多用于多线程编程的工具类。主要组件有线程池相关的类,像 ExecutorService;还有锁相关的类,比如 ReentrantLock;还有并发集合类,像 ConcurrentHashMap。 面试官:不错。那说说线程池的工作原理,线程池有哪些核心参数? 王铁牛:线程池就是预先创建一定数量的线程,当有任务提交时,就从线程池中获取线程来执行任务。核心参数有 corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、keepAliveTime(线程空闲存活时间)、TimeUnit(时间单位)、workQueue(任务队列)、threadFactory(线程工厂)、handler(任务拒绝策略)。 面试官:回答得挺全面。那在多线程环境下,如何保证数据的线程安全,有哪些方法? 王铁牛:可以使用 synchronized 关键字来对代码块或者方法进行同步,还有使用 ReentrantLock 显式锁。也可以使用并发集合类,像上面提到的 ConcurrentHashMap,它们内部已经实现了线程安全的机制。 面试官:很好,这一轮也很出色。

第三轮提问 面试官:现在来问一些框架相关的问题。Spring 的核心特性有哪些,说说你对 IoC 和 AOP 的理解。 王铁牛:Spring 的核心特性有 IoC(控制反转)和 AOP(面向切面编程)。IoC 就是把对象的创建和依赖关系的管理交给 Spring 容器,这样可以降低代码的耦合度。AOP 就是在不修改原有代码的基础上,对程序进行增强,比如实现日志记录、事务管理等功能。 面试官:理解得还可以。那 Spring Boot 和 Spring 有什么区别和联系,Spring Boot 的优势在哪里? 王铁牛:Spring Boot 是基于 Spring 构建的,它简化了 Spring 应用的开发过程。Spring 配置比较繁琐,而 Spring Boot 有很多自动配置,能快速搭建项目,减少了很多样板代码,提高了开发效率。 面试官:那 MyBatis 是如何实现数据库操作的,它的核心组件有哪些? 王铁牛:MyBatis 通过映射文件或者注解来定义 SQL 语句,然后通过 SqlSession 来执行这些 SQL 语句。核心组件有 SqlSessionFactory、SqlSession、Mapper 接口和映射文件。 面试官:整体表现不错。不过我还想再问一个分布式相关的问题,Dubbo 的工作原理是怎样的? 王铁牛:嗯……Dubbo 就是……就是能实现远程调用的,具体原理我有点说不太清楚。 面试官:没关系。那再问一个消息队列的问题,RabbitMQ 的消息确认机制是怎样的? 王铁牛:这个……我好像有点印象,但是不太能说得准确。 面试官:最后问一个任务调度的问题,xxl - job 的执行流程是怎样的? 王铁牛:这个我也不太清楚。

面试结束后,面试官看着王铁牛说:“今天的面试就到这里。你在前面关于 Java 核心知识、JUC、多线程以及部分框架基础问题上回答得很不错,看得出你有一定的技术基础。不过在分布式、消息队列和任务调度这些方面的知识掌握得不够扎实。我们会综合考虑你的表现,你先回家等通知吧。”

问题答案详细解析

  1. Java 中基本数据类型有哪些?
    • Java 中有 8 种基本数据类型,分为 4 类:
      • 整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节)。
      • 浮点类型:float(4 字节)、double(8 字节)。
      • 字符类型:char(2 字节)。
      • 布尔类型:boolean(理论上 1 位,但在 Java 中通常按 1 字节处理)。
  2. Java 的访问修饰符有哪些,它们的作用范围是怎样的?
    • public:可以被所有类访问,没有访问限制。
    • protected:可以被同一包内的类以及不同包的子类访问。
    • default(默认,不写修饰符时):只能被同一包内的类访问。
    • private:只能在本类中访问,其他类无法访问该类的私有成员。
  3. Java 中多态的实现方式有哪些?
    • 方法重载(Overloading):在一个类中可以有多个方法名相同但参数列表不同(参数个数、参数类型、参数顺序不同)的方法。调用时根据传入的参数来决定调用哪个方法。
    • 方法重写(Overriding):子类重写父类的方法,要求方法名、参数列表和返回值类型都相同。通过父类引用指向子类对象,调用该方法时会执行子类重写后的方法。
  4. 什么是 JUC,它包含哪些主要的组件?
    • JUC 是 java.util.concurrent 包,是 Java 提供的用于多线程编程的工具包。主要组件包括:
      • 线程池相关类:如 ExecutorService 是线程池的核心接口,ThreadPoolExecutor 是其实现类,用于管理和执行线程任务。
      • 锁相关类:ReentrantLock 是可重入锁,提供了比 synchronized 更灵活的锁机制。
      • 并发集合类:ConcurrentHashMap 是线程安全的哈希表,CopyOnWriteArrayList 是线程安全的列表。
      • 同步器:CountDownLatch 用于让一个或多个线程等待其他线程完成操作;CyclicBarrier 用于让一组线程互相等待,直到所有线程都到达某个屏障点。
  5. 线程池的工作原理,线程池有哪些核心参数?
    • 工作原理:线程池预先创建一定数量的线程,当有任务提交时,会按照以下规则处理:
      • 如果线程池中的线程数量小于核心线程数(corePoolSize),则创建新的线程来执行任务。
      • 如果线程数量达到核心线程数,任务会被放入任务队列(workQueue)中等待。
      • 如果任务队列已满,且线程数量小于最大线程数(maximumPoolSize),则创建新的线程来执行任务。
      • 如果线程数量达到最大线程数,任务队列也已满,会根据任务拒绝策略(handler)来处理新提交的任务。
    • 核心参数:
      • corePoolSize:核心线程数,线程池长期保持的线程数量。
      • maximumPoolSize:最大线程数,线程池允许的最大线程数量。
      • keepAliveTime:线程空闲存活时间,当线程空闲时间超过该值时,会被销毁,直到线程数量达到核心线程数。
      • TimeUnit:时间单位,用于指定 keepAliveTime 的时间单位。
      • workQueue:任务队列,用于存储等待执行的任务,常见的有 ArrayBlockingQueue、LinkedBlockingQueue 等。
      • threadFactory:线程工厂,用于创建线程。
      • handler:任务拒绝策略,当线程池和任务队列都满时,对新提交任务的处理方式,常见的有 AbortPolicy(直接抛出异常)、CallerRunsPolicy(让提交任务的线程执行任务)等。
  6. 在多线程环境下,如何保证数据的线程安全,有哪些方法?
    • 使用 synchronized 关键字:可以修饰代码块或者方法,当一个线程访问被 synchronized 修饰的代码时,其他线程需要等待该线程执行完才能访问。
    • 使用 ReentrantLock 显式锁:通过 lock() 方法加锁,unlock() 方法解锁,可以实现更灵活的锁控制,如可重入、可中断等。
    • 使用并发集合类:如 ConcurrentHashMap、CopyOnWriteArrayList 等,它们内部实现了线程安全的机制,在多线程环境下可以安全地进行读写操作。
    • 使用原子类:如 AtomicInteger、AtomicLong 等,它们基于 CAS(Compare - And - Swap)操作实现,保证了对变量的原子性操作。
  7. Spring 的核心特性有哪些,说说你对 IoC 和 AOP 的理解。
    • Spring 的核心特性主要是 IoC(控制反转)和 AOP(面向切面编程)。
    • IoC(控制反转):传统的对象创建和依赖关系管理是在代码中手动完成的,而 IoC 把这些工作交给 Spring 容器。容器负责创建对象,并将对象之间的依赖关系注入到对象中。这样可以降低代码的耦合度,提高代码的可维护性和可测试性。
    • AOP(面向切面编程):在不修改原有代码的基础上,对程序进行增强。通过定义切面(Aspect),在特定的切入点(Pointcut)执行增强逻辑(Advice),比如实现日志记录、事务管理、权限验证等功能。
  8. Spring Boot 和 Spring 有什么区别和联系,Spring Boot 的优势在哪里?
    • 联系:Spring Boot 是基于 Spring 构建的,它继承了 Spring 的核心特性,如 IoC 和 AOP。
    • 区别:Spring 配置比较繁琐,需要大量的 XML 配置文件或者 Java 配置类来进行配置。而 Spring Boot 有很多自动配置,通过约定大于配置的原则,能快速搭建项目,减少了很多样板代码。
    • 优势:
      • 快速搭建项目:通过 Spring Initializr 可以快速生成项目骨架,集成常用的依赖。
      • 自动配置:Spring Boot 会根据项目中引入的依赖自动进行配置,减少了手动配置的工作量。
      • 嵌入式服务器:可以将 Tomcat、Jetty 等服务器嵌入到项目中,方便开发和部署。
      • 生产级特性:提供了如监控、健康检查等生产级特性,方便对应用进行管理和维护。
  9. MyBatis 是如何实现数据库操作的,它的核心组件有哪些?
    • 实现数据库操作的方式:MyBatis 通过映射文件(XML 文件)或者注解来定义 SQL 语句,然后通过 SqlSession 来执行这些 SQL 语句。开发人员可以在映射文件中编写 SQL 语句,并将其与 Java 方法进行映射,当调用 Java 方法时,MyBatis 会执行对应的 SQL 语句,并将结果映射到 Java 对象中。
    • 核心组件:
      • SqlSessionFactory:用于创建 SqlSession 对象,是 MyBatis 的核心工厂类,通常通过配置文件(如 mybatis-config.xml)来创建。
      • SqlSession:是 MyBatis 的核心接口,用于执行 SQL 语句、管理事务等操作。
      • Mapper 接口:定义了数据库操作的方法,MyBatis 会根据映射文件或者注解为 Mapper 接口生成实现类。
      • 映射文件:包含了 SQL 语句和参数映射、结果映射等信息,是 MyBatis 实现数据库操作的关键。
  10. Dubbo 的工作原理是怎样的?
    • Dubbo 是一个分布式服务框架,主要由服务提供者(Provider)、服务消费者(Consumer)、注册中心(Registry)和监控中心(Monitor)组成。工作原理如下:
      • 服务提供者启动时,向注册中心注册自己提供的服务。
      • 服务消费者启动时,向注册中心订阅自己需要的服务,注册中心返回服务提供者的地址列表。
      • 服务消费者从地址列表中选择一个服务提供者,发起远程调用。
      • 服务提供者接收到请求后,执行相应的服务方法,并将结果返回给服务消费者。
      • 服务提供者和服务消费者在调用过程中,会将调用信息发送给监控中心,监控中心用于统计和监控服务的调用情况。
  11. RabbitMQ 的消息确认机制是怎样的?
    • RabbitMQ 的消息确认机制主要分为生产者确认和消费者确认。
    • 生产者确认:
      • 异步确认:生产者发送消息后,RabbitMQ 会异步返回一个确认消息(ConfirmCallback),生产者可以通过监听这个确认消息来判断消息是否发送成功。
      • 同步确认:生产者发送消息后,调用 waitForConfirms() 方法等待 RabbitMQ 的确认,直到收到确认消息或者超时。
    • 消费者确认:
      • 自动确认:消费者收到消息后,RabbitMQ 会自动将消息标记为已消费。
      • 手动确认:消费者收到消息后,需要手动调用 basicAck() 方法来确认消息已消费,或者调用 basicNack() 或 basicReject() 方法来拒绝消息。
  12. xxl - job 的执行流程是怎样的?
    • xxl - job 是一个分布式任务调度平台,执行流程如下:
      • 任务配置:在调度中心配置任务信息,包括任务的执行时间、执行器、任务参数等。
      • 任务注册:执行器启动时,会向调度中心注册自己的信息,包括执行器名称、地址等。
      • 任务调度:调度中心根据任务的配置信息,在指定的时间触发任务。
      • 任务分发:调度中心将任务信息发送给对应的执行器。
      • 任务执行:执行器接收到任务信息后,根据任务的类型(如 Java 方法、Shell 脚本等)执行任务。
      • 结果反馈:执行器将任务的执行结果(成功、失败等)反馈给调度中心,调度中心记录任务的执行状态。