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

23 阅读10分钟

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

王铁牛怀揣着紧张与期待,坐在了互联网大厂的面试间里,对面是神情严肃的面试官,一场对 Java 核心知识、各类框架和中间件的考验即将开始。

第一轮面试开始 面试官:首先问几个 Java 基础问题。Java 中基本数据类型有哪些? 王铁牛:这个我知道,Java 基本数据类型有 byte、short、int、long、float、double、char、boolean。 面试官:不错。那 String 是基本数据类型吗,它有什么特点? 王铁牛:String 不是基本数据类型,它是引用类型。String 是不可变的,一旦创建,它的值不能被改变,如果对 String 进行修改,实际上是创建了一个新的 String 对象。 面试官:很好。那说说 Java 中的多态是如何实现的? 王铁牛:多态主要通过继承和接口实现。有方法重载和方法重写,方法重载是在一个类中,有多个方法名相同但参数不同;方法重写是子类重写父类的方法,通过父类引用指向子类对象,调用方法时会根据实际的对象类型来执行相应的方法。 面试官:回答得很清晰,基础掌握得不错。

第二轮面试开始 面试官:接下来聊聊 JUC 和多线程。什么是线程安全,如何保证线程安全? 王铁牛:线程安全就是当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。可以用 synchronized 关键字、Lock 接口来保证线程安全。 面试官:那说说线程池的好处和常用的线程池有哪些? 王铁牛:线程池的好处是可以降低资源消耗,提高响应速度,便于线程管理。常用的线程池有 FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。 面试官:在实际业务中,如果线程池的任务队列满了,会发生什么? 王铁牛:呃……这个……好像会有一些处理策略,具体的我有点记不清了。 面试官:这里需要注意,当任务队列满了,会根据线程池设置的拒绝策略来处理新任务。你这部分知识掌握得不够扎实。

第三轮面试开始 面试官:现在谈谈框架相关的。Spring 的核心特性有哪些? 王铁牛:Spring 的核心特性有 IoC(控制反转)和 AOP(面向切面编程)。IoC 是把对象的创建和依赖关系的管理交给 Spring 容器,AOP 是在不修改原有代码的基础上,对程序进行增强。 面试官:Spring Boot 相对于 Spring 有什么优势? 王铁牛:Spring Boot 简化了 Spring 项目的搭建和开发,它有自动配置功能,能快速集成各种依赖,减少了大量的配置文件。 面试官:MyBatis 中如何实现多表查询? 王铁牛:这个……我知道可以用关联查询,具体怎么写我有点模糊了。 面试官:MyBatis 实现多表查询可以通过关联查询(如嵌套查询、嵌套结果),你对这部分实践可能不足。还有 Dubbo 是做什么的,它的工作原理能说一下吗? 王铁牛:Dubbo 好像是个分布式服务框架,原理嘛……我不太清楚。 面试官:Dubbo 用于实现分布式系统中的服务调用,它有服务注册与发现、远程调用等机制。你对这些框架的理解还不够深入。

面试结束,面试官看着王铁牛说:“今天的面试就到这里,你对一些基础的 Java 知识掌握得还可以,但在 JUC、线程池的实际应用,以及框架的深入理解和实践方面还有所欠缺。你先回家等通知吧,后续如果有进一步的消息,我们会及时联系你。”

问题答案详细解析

  1. Java 中基本数据类型有哪些?
    • Java 有 8 种基本数据类型,分为 4 类:
      • 整数类型:byte(1 字节,-128 到 127)、short(2 字节,-32768 到 32767)、int(4 字节,-2147483648 到 2147483647)、long(8 字节,范围更大)。
      • 浮点类型:float(4 字节,单精度)、double(8 字节,双精度)。
      • 字符类型:char(2 字节,用于存储单个字符)。
      • 布尔类型:boolean(只有 true 和 false 两个值)。
  2. String 是基本数据类型吗,它有什么特点?
    • String 不是基本数据类型,是引用类型。它的特点如下:
      • 不可变性:String 对象一旦创建,其值不能被改变。例如,当执行 String str = "hello"; str = str + " world"; 时,实际上是创建了一个新的 String 对象 "hello world",原来的 "hello" 对象依然存在于内存中。
      • 常量池:为了节省内存,相同内容的 String 常量会共享同一个内存地址。如 String s1 = "abc"; String s2 = "abc";,s1 和 s2 指向常量池中的同一个对象。
  3. Java 中的多态是如何实现的?
    • 多态主要通过以下两种方式实现:
      • 方法重载(Overloading):在一个类中,多个方法可以有相同的名称,但参数列表不同(参数的类型、个数或顺序不同)。例如:
public class OverloadExample {
    public int add(int a, int b) {
        return a + b;
    }
    public double add(double a, double b) {
        return a + b;
    }
}
    - 方法重写(Overriding)和向上转型:子类继承父类并重写父类的方法,通过父类引用指向子类对象,调用方法时会根据实际的对象类型来执行相应的方法。例如:
class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound");
    }
}
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}
// 使用时
Animal animal = new Dog();
animal.makeSound(); // 输出 Dog barks
  1. 什么是线程安全,如何保证线程安全?
    • 线程安全:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。
    • 保证线程安全的方法:
      • synchronized 关键字:可以修饰方法或代码块,保证同一时刻只有一个线程可以访问被修饰的方法或代码块。例如:
public class SynchronizedExample {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
}
    - Lock 接口:Java.util.concurrent.locks 包下的 Lock 接口提供了更灵活的锁机制,如 ReentrantLock。例如:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}
  1. 线程池的好处和常用的线程池有哪些?
    • 线程池的好处:
      • 降低资源消耗:减少了线程创建和销毁的开销,因为线程可以重复使用。
      • 提高响应速度:当有新任务提交时,线程池中如果有空闲线程可以立即执行任务,无需等待线程创建。
      • 便于线程管理:可以对线程进行统一的分配、监控和调优。
    • 常用的线程池:
      • FixedThreadPool:固定大小的线程池,线程数量固定,当有新任务提交时,如果线程池中有空闲线程则执行,否则任务会在队列中等待。
      • CachedThreadPool:可缓存的线程池,线程数量不固定,会根据任务的数量动态创建和销毁线程。当有新任务提交时,如果有空闲线程则使用,否则创建新线程。
      • ScheduledThreadPool:定时任务线程池,可用于执行定时任务或周期性任务。
      • SingleThreadExecutor:单线程线程池,只有一个线程在工作,保证任务按顺序执行。
  2. 在实际业务中,如果线程池的任务队列满了,会发生什么? 当线程池的任务队列满了,会根据线程池设置的拒绝策略来处理新任务,Java 提供了以下几种拒绝策略:
    • AbortPolicy(默认):直接抛出 RejectedExecutionException 异常,阻止系统正常运行。
    • CallerRunsPolicy:由调用线程(提交任务的线程)来执行该任务。
    • DiscardPolicy:直接丢弃新任务,不做任何处理。
    • DiscardOldestPolicy:丢弃任务队列中最老的任务,然后尝试重新提交新任务。
  3. Spring 的核心特性有哪些?
    • IoC(控制反转):把对象的创建和依赖关系的管理交给 Spring 容器,而不是在代码中手动创建和管理对象。例如,原来在代码中使用 UserService userService = new UserServiceImpl(); 创建对象,在 Spring 中可以通过配置文件或注解让 Spring 容器来创建和管理 UserService 对象。
    • AOP(面向切面编程):在不修改原有代码的基础上,对程序进行增强,如日志记录、事务管理等。通过定义切面(Aspect)、切点(Pointcut)和通知(Advice)来实现。例如,在方法执行前后添加日志记录的功能。
  4. Spring Boot 相对于 Spring 有什么优势?
    • 简化配置:Spring Boot 有自动配置功能,能根据项目中添加的依赖自动进行配置,减少了大量的 XML 配置文件。例如,添加了 Spring Data JPA 的依赖,Spring Boot 会自动配置数据源、JPA 等相关信息。
    • 快速集成:可以快速集成各种依赖,通过添加相应的 Starter 依赖,Spring Boot 会自动处理依赖之间的版本兼容性等问题。
    • 内置服务器:Spring Boot 内置了 Tomcat、Jetty 等服务器,不需要额外部署服务器,直接运行主类即可启动项目。
  5. MyBatis 中如何实现多表查询?
    • 关联查询(嵌套查询和嵌套结果):
      • 嵌套查询:通过在一个查询中调用另一个查询来实现多表查询。例如,查询用户信息时同时查询用户的订单信息,先查询用户信息,再根据用户 ID 查询订单信息。
<select id="getUserWithOrders" resultMap="UserWithOrdersResultMap">
    SELECT * FROM users WHERE user_id = #{userId}
</select>
<select id="getOrdersByUserId" resultType="Order">
    SELECT * FROM orders WHERE user_id = #{userId}
</select>
<resultMap id="UserWithOrdersResultMap" type="User">
    <id property="userId" column="user_id"/>
    <result property="userName" column="user_name"/>
    <collection property="orders" ofType="Order" select="getOrdersByUserId" column="user_id"/>
</resultMap>
    - 嵌套结果:将多个表的查询结果映射到一个复杂的对象中。例如:
<select id="getUserWithOrders" resultMap="UserWithOrdersResultMap">
    SELECT u.user_id, u.user_name, o.order_id, o.order_name 
    FROM users u 
    LEFT JOIN orders o ON u.user_id = o.user_id 
    WHERE u.user_id = #{userId}
</select>
<resultMap id="UserWithOrdersResultMap" type="User">
    <id property="userId" column="user_id"/>
    <result property="userName" column="user_name"/>
    <collection property="orders" ofType="Order">
        <id property="orderId" column="order_id"/>
        <result property="orderName" column="order_name"/>
    </collection>
</resultMap>
  1. Dubbo 是做什么的,它的工作原理能说一下吗?
    • Dubbo 是一个高性能的分布式服务框架,用于实现分布式系统中的服务调用。它可以将不同的服务提供者和服务消费者连接起来,实现远程服务调用。
    • 工作原理:
      • 服务注册:服务提供者启动时,将自己提供的服务信息(如服务接口、服务地址等)注册到服务注册中心(如 ZooKeeper)。
      • 服务发现:服务消费者启动时,从服务注册中心获取服务提供者的信息。
      • 远程调用:服务消费者根据获取的服务提供者信息,通过网络调用服务提供者的服务。Dubbo 支持多种远程调用协议,如 Dubbo 协议、HTTP 协议等。
      • 服务监控:Dubbo 提供了服务监控功能,可以监控服务的调用情况,如调用次数、调用时间等。