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

72 阅读7分钟

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

王铁牛怀揣着紧张又期待的心情,走进了互联网大厂的面试会议室。严肃的面试官坐在对面,一场考验即将开始。

第一轮提问 面试官:首先问几个 Java 核心知识的问题。Java 中基本数据类型有哪些? 王铁牛:这个我知道,Java 基本数据类型有 byte、short、int、long、float、double、char、boolean。 面试官:回答得不错。那说说重载和重写的区别。 王铁牛:重载是在一个类中,方法名相同但参数列表不同;重写是子类重写父类的方法,方法名、参数列表和返回值类型都一样。 面试官:很好,基础很扎实。那在 Java 中,final 关键字有什么作用? 王铁牛:final 修饰类时,类不能被继承;修饰方法时,方法不能被重写;修饰变量时,变量就成了常量,不能再被赋值。 面试官:非常棒,看来你对 Java 核心知识掌握得很牢固。

第二轮提问 面试官:接下来聊聊 JUC 和多线程相关的。说说线程的几种状态。 王铁牛:线程有新建、就绪、运行、阻塞和死亡这几种状态。 面试官:不错。那线程池有什么作用,常用的线程池有哪些? 王铁牛:线程池可以复用线程,减少创建和销毁线程的开销。常用的线程池有 FixedThreadPool、CachedThreadPool、ScheduledThreadPool 和 SingleThreadExecutor。 面试官:回答得挺全面。那在多线程环境下,HashMap 为什么不安全? 王铁牛:嗯……这个嘛,好像是会有数据不一致的问题,具体的我有点说不太清楚。 面试官:这里要注意,在多线程下,HashMap 扩容时可能会形成环形链表,导致死循环,还有可能数据丢失。不过你前面回答得还行。

第三轮提问 面试官:现在问一些框架和中间件的问题。Spring 的核心特性有哪些? 王铁牛:Spring 的核心特性有依赖注入和面向切面编程。 面试官:很好。那 Spring Boot 相对于 Spring 有什么优势? 王铁牛:Spring Boot 简化了配置,有自动配置功能,还能快速搭建项目。 面试官:不错。那 MyBatis 中 #{} 和 {} 的区别是什么? **王铁牛**:这个……我记得一个是预编译,一个不是,但具体哪个是哪个我有点乱了。 **面试官**:#{} 是预编译处理,能防止 SQL 注入,{} 是直接替换,可能会有 SQL 注入风险。还有 Dubbo 是做什么的,你说说。 王铁牛:Dubbo 好像是个分布式服务框架,具体的工作原理我不太清楚。 面试官:Dubbo 主要用于实现分布式服务的远程调用和服务治理。你整体有一定的基础,但对于一些细节和复杂的知识点掌握得还不够扎实。你先回家等通知吧,后续有结果会及时联系你。

问题答案详解

  1. Java 基本数据类型
    • 数值型
      • 整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节)。
      • 浮点类型:float(4 字节)、double(8 字节)。
    • 字符型:char(2 字节),用于表示单个字符。
    • 布尔型:boolean,只有 true 和 false 两个值。
  2. 重载和重写的区别
    • 重载(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)**:发生在子类和父类之间,子类重写父类的方法。方法名、参数列表和返回值类型必须相同(Java 5 以后返回值类型可以是父类方法返回值类型的子类),访问修饰符不能比父类的更严格。例如:
class Parent {
    public void print() {
        System.out.println("Parent method");
    }
}
class Child extends Parent {
    @Override
    public void print() {
        System.out.println("Child method");
    }
}
  1. final 关键字的作用
    • 修饰类:该类不能被继承,例如 final class FinalClass {},其他类无法继承 FinalClass
    • 修饰方法:该方法不能被重写,例如在父类中 public final void finalMethod() {},子类不能重写这个方法。
    • 修饰变量:变量成为常量,一旦赋值就不能再改变。如果是引用类型,引用不能再指向其他对象,但对象的内容可以改变。例如 final int NUM = 10;
  2. 线程的几种状态
    • 新建(New):线程对象被创建,还未调用 start() 方法。例如 Thread t = new Thread();
    • 就绪(Runnable):调用 start() 方法后,线程进入就绪状态,等待获取 CPU 时间片。
    • 运行(Running):线程获得 CPU 时间片,正在执行 run() 方法。
    • 阻塞(Blocked):线程因为某些原因(如等待 I/O、等待锁等)暂时停止执行,让出 CPU 时间片。
    • 死亡(Terminated):线程执行完 run() 方法或者因异常退出,生命周期结束。
  3. 线程池的作用和常用线程池
    • 作用
      • 降低资源消耗:复用线程,减少线程创建和销毁的开销。
      • 提高响应速度:任务到达时,直接从线程池中获取线程执行,无需等待线程创建。
      • 便于管理:可以对线程进行统一的分配、调优和监控。
    • 常用线程池
      • FixedThreadPool:固定大小的线程池,线程数量固定,当有新任务提交时,如果线程池中有空闲线程则立即执行,否则任务会被放入队列等待。
      • CachedThreadPool:可缓存的线程池,线程数量不固定,会根据任务数量动态创建和回收线程。如果线程空闲时间超过 60 秒,会被回收。
      • ScheduledThreadPool:定时任务线程池,可用于执行定时任务和周期性任务。
      • SingleThreadExecutor:单线程线程池,只有一个线程执行任务,保证任务按顺序执行。
  4. 多线程环境下 HashMap 不安全的原因
    • 扩容时形成环形链表:在多线程同时进行扩容操作时,可能会导致链表形成环形结构,当进行查找操作时会进入死循环。
    • 数据丢失:多个线程同时进行 put 操作时,可能会导致其中一个线程的数据被覆盖。
  5. Spring 的核心特性
    • 依赖注入(Dependency Injection,DI):将对象之间的依赖关系通过外部注入的方式实现,而不是在对象内部直接创建依赖对象。例如:
public class UserService {
    private UserDao userDao;
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}
- **面向切面编程(Aspect-Oriented Programming,AOP)**:将与业务无关的通用功能(如日志记录、事务管理等)从业务逻辑中分离出来,以切面的形式进行统一管理。

8. Spring Boot 相对于 Spring 的优势: - 简化配置:Spring Boot 提供了大量的自动配置,减少了 XML 配置文件和 Java 配置类的编写。 - 快速搭建项目:通过 Spring Initializr 可以快速创建一个 Spring Boot 项目,集成了常用的依赖。 - 嵌入式服务器:内置了 Tomcat、Jetty 等服务器,无需单独部署服务器。 - 监控和管理:提供了 Actuator 功能,方便对应用进行监控和管理。 9. MyBatis 中 #{} 和 ${} 的区别: - #{}:是预编译处理,MyBatis 会将 #{} 替换为占位符 ?,可以防止 SQL 注入。例如:

<select id="getUserById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>
- **${}**:是直接替换,会将 ${} 中的内容直接插入到 SQL 语句中,可能会导致 SQL 注入。例如:
<select id="getUserByColumnName" parameterType="String" resultType="User">
    SELECT * FROM users WHERE ${columnName} = 'value'
</select>
  1. Dubbo 的作用: Dubbo 是一个高性能的分布式服务框架,主要用于实现分布式服务的远程调用和服务治理。它提供了服务注册与发现、负载均衡、集群容错、远程调用等功能,帮助开发者构建分布式系统。例如,在一个大型电商系统中,商品服务、订单服务、用户服务等可以通过 Dubbo 进行远程调用,实现服务之间的解耦和高效协作。