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

61 阅读2分钟

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

严肃的面试官坐在办公桌后,面前放着王铁牛的简历,表情冷峻。王铁牛坐在对面,略显紧张,双手不自觉地捏着衣角。

第一轮提问 面试官:首先问几个 Java 核心知识的问题。Java 中基本数据类型有哪些? 王铁牛:嗯,有 byte、short、int、long、float、double、char、boolean。 面试官:回答正确,基础很扎实。那说说 Java 中自动装箱和拆箱的概念。 王铁牛:自动装箱就是把基本数据类型转换成对应的包装类,拆箱就是把包装类转换成基本数据类型,比如 Integer i = 10 就是自动装箱,int j = i 就是拆箱。 面试官:非常好。那在多线程环境下,如何保证变量的可见性? 王铁牛:可以使用 volatile 关键字,它能保证变量在多个线程之间的可见性。

第二轮提问 面试官:接下来聊聊 JUC 相关的。JUC 中 CountDownLatch 是做什么用的? 王铁牛:这个……我好像有点印象,它好像是能控制线程的数量吧。 面试官:你的回答不太准确。那再问你,CyclicBarrier 和 CountDownLatch 有什么区别? 王铁牛:嗯……它们好像都是和线程同步有关的,具体区别我不太清楚。 面试官:看来这块知识掌握得不够好。那说说 JUC 中常用的线程池有哪些? 王铁牛:有固定大小线程池、单线程线程池,还有……还有其他的我记不太清了。

第三轮提问 面试官:现在问一些框架相关的。Spring 中 Bean 的生命周期是怎样的? 王铁牛:这个……好像有创建、初始化,然后就可以使用了,后面的我不太确定。 面试官:回答得不够完整。那 Spring Boot 如何实现自动配置的? 王铁牛:好像是通过一些配置文件,具体的我也说不清楚。 面试官:看来对 Spring Boot 的原理理解得不够深入。最后问你,MyBatis 中 #{} 和 ${} 的区别是什么? 王铁牛:我觉得它们好像都能传参数,具体区别不太明白。

面试官合上手中的笔记,面无表情地说:“今天的面试就到这里,你先回家等通知吧。我们会综合评估后给你反馈。”

答案解析

  1. Java 基本数据类型:Java 中有 8 种基本数据类型,分别是 4 种整数类型(byte 占 1 字节,取值范围 -128 到 127;short 占 2 字节;int 占 4 字节;long 占 8 字节),2 种浮点类型(float 占 4 字节,double 占 8 字节),1 种字符类型(char 占 2 字节)和 1 种布尔类型(boolean 只有 true 和 false 两个值)。
  2. 自动装箱和拆箱:自动装箱是 Java 编译器在基本数据类型和对应的包装类之间做的一个转化,如把 int 转化为 Integer,double 转化为 Double 等。拆箱则相反,是把包装类对象转化为基本数据类型。例如:
Integer i = 10; // 自动装箱,实际执行 Integer i = Integer.valueOf(10);
int j = i; // 自动拆箱,实际执行 int j = i.intValue();
  1. 多线程环境下保证变量可见性:使用 volatile 关键字,它能保证一个变量在多个线程之间的可见性。当一个变量被声明为 volatile 时,它会保证对该变量的写操作会立即刷新到主内存,读操作会从主内存中读取最新的值。例如:
public class VolatileExample {
    private volatile boolean flag = false;

    public void setFlag() {
        flag = true;
    }

    public boolean getFlag() {
        return flag;
    }
}
  1. JUC 中 CountDownLatch 的作用:CountDownLatch 是一个同步辅助类,它允许一个或多个线程等待直到在其他线程中一组操作执行完成。例如,主线程等待多个子线程完成任务后再继续执行:
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 完成任务");
                latch.countDown();
            }).start();
        }

        latch.await();
        System.out.println("所有任务完成,主线程继续执行");
    }
}
  1. CyclicBarrier 和 CountDownLatch 的区别
    • CountDownLatch 是一次性的,计数器的值只能在构造方法中初始化一次,之后不能再使用。而 CyclicBarrier 可以重复使用,当线程到达屏障点后,计数器会重置。
    • CountDownLatch 主要用于一个或多个线程等待其他线程完成操作,而 CyclicBarrier 主要用于多个线程相互等待,直到所有线程都到达某个同步点后再一起继续执行。
  2. JUC 中常用的线程池
    • FixedThreadPool:固定大小的线程池,线程数量固定,当有新任务提交时,如果线程池中有空闲线程则立即执行,否则任务会被放入队列中等待。
    • SingleThreadExecutor:单线程的线程池,只有一个线程在工作,所有任务按顺序执行。
    • CachedThreadPool:可缓存的线程池,如果线程池的线程数量超过了处理任务所需的线程,那么空闲线程会在一定时间后被回收。
    • ScheduledThreadPool:可以在指定延迟时间后执行任务或定期执行任务的线程池。
  3. Spring 中 Bean 的生命周期
    • 实例化:通过反射创建 Bean 的实例。
    • 属性赋值:为 Bean 的属性设置值。
    • 初始化:调用 Bean 的初始化方法,如实现 InitializingBean 接口的 afterPropertiesSet 方法或自定义的 init - method 方法。
    • 使用:Bean 可以被应用程序使用。
    • 销毁:当 Bean 不再使用时,调用销毁方法,如实现 DisposableBean 接口的 destroy 方法或自定义的 destroy - method 方法。
  4. Spring Boot 实现自动配置的原理:Spring Boot 基于 Spring 的条件注解(如 @ConditionalOnClass、@ConditionalOnMissingBean 等)和自动配置类(在 spring - factories 文件中配置)实现自动配置。当 Spring Boot 应用启动时,会扫描 classpath 下的 spring.factories 文件,加载其中定义的自动配置类。这些自动配置类会根据条件注解判断是否满足配置条件,如果满足则进行相应的配置。
  5. MyBatis 中 #{} 和 ${} 的区别
    • #{}:是预编译处理,MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 占位符,然后使用 PreparedStatement 进行参数设置,这样可以防止 SQL 注入攻击。
    • **:是字符串替换,MyBatis在处理{}**:是字符串替换,MyBatis 在处理 {} 时,会直接将 替换为变量的值,可能会导致SQL注入问题。例如在动态表名等场景下会使用{} 替换为变量的值,可能会导致 SQL 注入问题。例如在动态表名等场景下会使用 {},但要注意参数的安全性。例如:
<select id="selectByUsername" resultType="User">
    SELECT * FROM users WHERE username = #{username}
</select>
<select id="selectByTable" resultType="User">
    SELECT * FROM ${tableName} WHERE id = #{id}
</select>