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

28 阅读2分钟

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

王铁牛怀揣着对互联网大厂的憧憬,走进了面试房间。严肃的面试官坐在对面,一场紧张的面试拉开了帷幕。

第一轮提问 面试官:首先,我问你几个基础的Java核心知识问题。Java 中基本数据类型有哪些? 王铁牛:这个我知道,Java 基本数据类型有 byte、short、int、long、float、double、char、boolean。 面试官:不错,回答得很准确。那 Java 中如何实现多态? 王铁牛:多态主要通过继承和接口实现。父类引用指向子类对象,调用相同的方法会有不同的实现,这就是多态。 面试官:很好。那说说 String、StringBuilder 和 StringBuffer 的区别。 王铁牛:String 是不可变的,每次对 String 进行操作都会创建新的对象;StringBuilder 是非线程安全的,效率高;StringBuffer 是线程安全的,效率相对低一些。 面试官:非常棒,基础很扎实。

第二轮提问 面试官:接下来我问一些关于 JUC、JVM 和多线程的问题。JUC 包中常用的类有哪些? 王铁牛:嗯……有 ExecutorService 吧,还有……好像有个 Future 啥的。 面试官:那 JVM 的内存模型是怎样的? 王铁牛:这个……好像有堆、栈,还有别的啥,我有点记不太清了。 面试官:多线程中如何避免死锁? 王铁牛:这个嘛,我觉得就是别让线程一直等着,但是具体咋做我不太清楚。 面试官:这几个问题回答得不太理想,你还需要加强这方面的学习。

第三轮提问 面试官:最后问你一些关于框架和中间件的问题。Spring 框架的核心特性有哪些? 王铁牛:有 IoC 和 AOP,IoC 就是控制反转,AOP 是面向切面编程。 面试官:Spring Boot 如何实现自动配置的? 王铁牛:这个……好像是有一些配置文件啥的,具体我也说不太明白。 面试官:MyBatis 中 #{} 和 ${} 的区别是什么? 王铁牛:嗯……好像一个是预编译,一个不是,具体哪个是哪个我搞混了。 面试官:看来你对框架和中间件的理解还不够深入。

面试结束,面试官一脸严肃地对王铁牛说:“今天的面试就到这里,你先回家等通知吧。我们会综合评估你的表现,后续会通过邮件或者电话通知你结果。在等待的过程中,你也可以进一步巩固和学习相关的知识。”

问题答案

  1. Java 中基本数据类型有哪些? Java 有 8 种基本数据类型,分为 4 类:

    • 整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节)。
    • 浮点类型:float(4 字节)、double(8 字节)。
    • 字符类型:char(2 字节)。
    • 布尔类型:boolean(1 位)。
  2. Java 中如何实现多态? 多态的实现主要有以下两种方式:

    • 继承:通过父类引用指向子类对象,调用相同的方法会根据实际的子类对象调用不同的实现。例如:
class Animal {
    public void sound() {
        System.out.println("Animal makes a sound");
    }
}
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Dog barks");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.sound();
    }
}
- 接口:实现接口的不同类可以有不同的实现方式,通过接口引用指向实现类对象来实现多态。

3. 说说 String、StringBuilder 和 StringBuffer 的区别。 - String:是不可变的,一旦创建,其值不能被修改。每次对 String 进行操作(如拼接、替换等)都会创建新的 String 对象,会造成内存的浪费。例如:

String str = "Hello";
str = str + " World"; // 这里创建了新的 String 对象
- StringBuilder:是非线程安全的,在单线程环境下使用,效率较高。它是可变的,对其进行操作不会创建新的对象。例如:
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 直接在原对象上进行操作
- StringBuffer:是线程安全的,在多线程环境下使用。它也是可变的,但由于要保证线程安全,会有一些同步开销,效率相对 StringBuilder 较低。

4. JUC 包中常用的类有哪些? JUC(java.util.concurrent)包是 Java 提供的用于处理并发编程的包,常用的类有: - ExecutorService:线程池的接口,用于管理和执行线程任务。例如:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            executor.submit(() -> {
                System.out.println(Thread.currentThread().getName());
            });
        }
        executor.shutdown();
    }
}
- Future:表示异步计算的结果,可以通过它获取任务的执行结果。
- CountDownLatch:用于让一个或多个线程等待其他线程完成操作。
- Semaphore:用于控制同时访问某个资源的线程数量。

5. JVM 的内存模型是怎样的? JVM 内存模型主要分为以下几个区域: - 堆(Heap):是 JVM 中最大的一块内存区域,用于存储对象实例和数组。所有通过 new 创建的对象都存储在堆中,是线程共享的。 - 栈(Stack):每个线程都有自己的栈,用于存储局部变量、方法调用和返回值等。栈中的数据是线程私有的。 - 方法区(Method Area):用于存储类的信息、常量、静态变量等,是线程共享的。在 Java 8 之后,方法区被元空间(Metaspace)取代。 - 程序计数器(Program Counter Register):用于记录当前线程执行的字节码指令地址,是线程私有的。 - 本地方法栈(Native Method Stack):与栈类似,用于执行本地方法。

  1. 多线程中如何避免死锁? 死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象。可以通过以下方法避免死锁:

    • 按顺序加锁:所有线程都按照相同的顺序获取锁,避免出现循环等待的情况。
    • 限时加锁:使用带超时时间的锁,当获取锁的时间超过一定限制时,放弃锁的获取。
    • 减少锁的持有时间:尽量缩短线程持有锁的时间,减少死锁的可能性。
  2. Spring 框架的核心特性有哪些? Spring 框架的核心特性主要有:

    • IoC(Inversion of Control,控制反转):将对象的创建和依赖关系的管理交给 Spring 容器,而不是由对象自己负责。通过依赖注入(Dependency Injection)实现,有构造函数注入、属性注入等方式。
    • AOP(Aspect Oriented Programming,面向切面编程):将与业务逻辑无关的横切关注点(如日志、事务管理等)从业务逻辑中分离出来,提高代码的可维护性和复用性。
  3. Spring Boot 如何实现自动配置的? Spring Boot 实现自动配置主要基于以下几个方面:

    • @EnableAutoConfiguration 注解:该注解会触发 Spring Boot 的自动配置机制,它会根据类路径下的依赖和配置信息,自动配置 Spring 应用。
    • SpringFactoriesLoader:Spring Boot 会通过 SpringFactoriesLoader 加载 META - INF/spring.factories 文件中的自动配置类。
    • 条件注解:如 @ConditionalOnClass、@ConditionalOnMissingBean 等,用于根据不同的条件决定是否加载某个自动配置类。
  4. MyBatis 中 #{} 和 ${} 的区别是什么?

    • #{}:是预编译处理,MyBatis 会将 #{} 解析为一个占位符(?),在执行 SQL 时会将参数进行安全的处理,防止 SQL 注入。例如:
<select id="getUserById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>
- ${}:是字符串替换,MyBatis 会将 ${} 直接替换为参数的值,可能会导致 SQL 注入。例如:
<select id="getUserByTableName" parameterType="String" resultType="User">
    SELECT * FROM ${tableName}
</select>

所以在实际开发中,尽量使用 #{} 来避免 SQL 注入问题。