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

67 阅读9分钟

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

在互联网大厂宽敞明亮的面试室内,严肃的面试官正襟危坐,对面坐着略显紧张的求职者王铁牛。面试正式开始。

第一轮提问 面试官:首先问几个 Java 核心知识的问题。Java 中基本数据类型有哪些? 王铁牛:嗯,有 byte、short、int、long、float、double、char、boolean。 面试官:回答得不错。那说说 String 类为什么是不可变的? 王铁牛:因为 String 类是用 final 修饰的,它的底层是一个被 final 修饰的字符数组,一旦创建就不能修改。 面试官:很好。再问一个,Java 中的多态是如何实现的? 王铁牛:多态的实现主要有两种方式,一种是方法重载,在同一个类中可以有多个同名但参数不同的方法;另一种是方法重写,子类重写父类的方法,通过父类引用指向子类对象,调用方法时会根据实际的对象类型来执行相应的方法。 面试官:非常棒,看来你对 Java 核心知识掌握得很扎实。

第二轮提问 面试官:接下来聊聊 JUC、JVM 和多线程相关的内容。JUC 包下常用的类有哪些? 王铁牛:有 CountDownLatch、CyclicBarrier、Semaphore 这些,还有像 Executors 工具类可以用来创建线程池。 面试官:不错。那讲讲 JVM 的内存模型。 王铁牛:嗯……JVM 内存模型有堆、栈、方法区,还有程序计数器啥的。堆是存放对象实例的地方,栈主要是存放局部变量和方法调用的信息。 面试官:那在多线程环境下,如何保证线程安全? 王铁牛:可以用 synchronized 关键字,它可以保证同一时刻只有一个线程能访问被修饰的代码块或方法;还可以用 Lock 接口的实现类,像 ReentrantLock。 面试官:回答得还行,对这部分知识有一定的了解。

第三轮提问 面试官:现在问一些关于框架和中间件的问题。Spring 框架中 IOC 和 AOP 的原理是什么? 王铁牛:IOC 嘛,就是控制反转,把对象的创建和依赖关系的管理交给 Spring 容器。AOP 就是面向切面编程,通过动态代理的方式在目标方法执行前后插入一些额外的逻辑。 面试官:那 Spring Boot 相对于 Spring 有哪些优势? 王铁牛:Spring Boot 有自动配置,能减少很多配置文件的编写,还内置了服务器,启动项目更方便。 面试官:MyBatis 中如何实现动态 SQL? 王铁牛:MyBatis 可以用 、、、、 这些标签来实现动态 SQL。 面试官:不错,对框架这块也有一定认识。那再问一个,Dubbo 的服务注册与发现机制是怎样的? 王铁牛:嗯……就是服务提供者把自己的服务信息注册到注册中心,服务消费者从注册中心获取服务提供者的信息,然后去调用服务。具体的……我有点说不太清楚了。 面试官:没关系。整体来说,你前面回答得还可以,但对于一些复杂问题的理解还不够深入。你先回家等通知吧,后续如果有消息会及时联系你。

答案详解

  1. Java 基本数据类型:Java 中有 8 种基本数据类型,其中 4 种整数类型(byte 占 1 字节,范围 -128 到 127;short 占 2 字节;int 占 4 字节,是最常用的整数类型;long 占 8 字节,通常在表示较大整数时使用),2 种浮点类型(float 占 4 字节,double 占 8 字节,double 精度更高),1 种字符类型(char 占 2 字节,用于表示单个字符),1 种布尔类型(boolean 只有两个值 true 和 false)。
  2. String 类不可变的原因:String 类被 final 修饰,意味着它不能被继承。其底层是一个被 final 修饰的字符数组 value,final 修饰数组表示引用不可变,即不能再指向其他数组对象,但数组中的元素值是可以改变的。不过 String 类没有提供修改数组元素的方法,所以一旦 String 对象创建,其值就不能被修改。这样设计的好处有安全性、缓存 hash 值、线程安全等。
  3. Java 多态的实现方式
    • 方法重载:在同一个类中,方法名相同但参数列表不同(参数的类型、个数或顺序不同),与返回值类型无关。调用时根据传入的参数来决定执行哪个方法。
    • 方法重写:子类继承父类后,重写父类的方法,方法名、参数列表和返回值类型都要与父类的方法一致(返回值类型可以是父类方法返回值类型的子类,这称为协变返回类型)。通过父类引用指向子类对象,在运行时会根据实际的对象类型来调用相应的方法,实现了运行时多态。
  4. JUC 包下常用的类
    • CountDownLatch:一个同步辅助类,允许一个或多个线程等待其他线程完成操作。通过构造函数传入一个初始计数值,当计数值减为 0 时,等待的线程才会继续执行。
    • CyclicBarrier:让一组线程达到一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续执行。它可以循环使用。
    • Semaphore:用来控制同时访问特定资源的线程数量,通过 acquire() 方法获取许可,release() 方法释放许可。
    • Executors:是一个工具类,提供了创建各种线程池的静态方法,如 newFixedThreadPool() 创建固定大小的线程池,newCachedThreadPool() 创建可缓存的线程池等。
  5. JVM 内存模型
    • :是 JVM 中最大的一块内存区域,所有对象实例和数组都在此分配内存。它是垃圾回收的主要区域,又可以分为新生代和老年代,新生代还可以进一步分为 Eden 区、Survivor 区。
    • :每个线程都有自己的栈,栈中存储局部变量、方法调用的信息(如方法的返回地址、局部变量表、操作数栈等)。栈的生命周期与线程相同,当线程结束时,栈也会被销毁。
    • 方法区:用于存储类的元数据信息,如类的定义、常量池、静态变量等。在 JDK 1.8 之前,方法区也被称为永久代,JDK 1.8 及以后用元空间代替了永久代。
    • 程序计数器:是一块较小的内存区域,它可以看作是当前线程所执行的字节码的行号指示器,每个线程都有一个独立的程序计数器。
  6. 多线程环境下保证线程安全的方法
    • synchronized 关键字:可以修饰方法或代码块。当修饰实例方法时,锁的是当前对象实例;当修饰静态方法时,锁的是当前类的 Class 对象;当修饰代码块时,需要指定一个锁对象。它是基于 JVM 的内置锁机制,在进入同步代码块或方法时会获取锁,执行完后释放锁,保证同一时刻只有一个线程能访问。
    • Lock 接口的实现类:如 ReentrantLock,它是一个可重入锁,需要手动获取和释放锁。通过 lock() 方法获取锁,unlock() 方法释放锁,通常在 finally 块中释放锁以确保锁一定会被释放。与 synchronized 相比,它提供了更灵活的锁机制,如可中断锁、公平锁等。
  7. Spring 框架中 IOC 和 AOP 的原理
    • IOC(控制反转):核心思想是将对象的创建和依赖关系的管理从代码中转移到 Spring 容器中。Spring 容器通过读取配置文件(如 XML 配置文件或 Java 注解)来创建和管理对象,对象之间的依赖关系也由容器来注入。实现方式主要有依赖注入(DI),包括构造函数注入、属性注入等。
    • AOP(面向切面编程):通过动态代理的方式在目标方法执行前后插入额外的逻辑,如日志记录、事务管理等。Spring AOP 支持两种代理方式,JDK 动态代理和 CGLIB 代理。JDK 动态代理基于接口实现,而 CGLIB 代理基于继承实现。
  8. Spring Boot 相对于 Spring 的优势
    • 自动配置:Spring Boot 提供了大量的自动配置类,根据项目中引入的依赖自动进行配置,减少了开发者手动编写配置文件的工作量。
    • 内置服务器:Spring Boot 内置了 Tomcat、Jetty 等服务器,开发者可以直接将项目打包成可执行的 JAR 文件,通过 java -jar 命令启动项目,无需部署到外部服务器。
    • 简化依赖管理:Spring Boot 提供了一系列的 Starter 依赖,将相关的依赖打包在一起,开发者只需要引入相应的 Starter 依赖,就可以自动引入所需的依赖。
  9. MyBatis 中实现动态 SQL 的方式:MyBatis 提供了多种标签来实现动态 SQL。
    • 标签:用于条件判断,根据条件决定是否包含某段 SQL 语句。
    • 、、 标签:类似于 Java 中的 switch - case 语句,根据条件选择执行某一段 SQL 语句。
    • 标签:用于遍历集合或数组,通常用于批量操作,如批量插入、批量删除等。
  10. Dubbo 的服务注册与发现机制:Dubbo 采用注册中心来实现服务的注册与发现。服务提供者在启动时,将自己的服务信息(如服务接口、服务地址等)注册到注册中心。服务消费者在启动时,从注册中心订阅所需的服务信息,注册中心会将服务提供者的信息推送给服务消费者。当服务提供者的信息发生变化时,注册中心会及时通知服务消费者。常用的注册中心有 Zookeeper、Redis 等。