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

39 阅读3分钟

在互联网大厂的一间明亮的面试室内,严肃的面试官坐在桌前,对面是略显紧张的求职者王铁牛。面试正式开始。

第一轮面试 面试官:我们先从 Java 核心知识开始。Java 中基本数据类型有哪些? 王铁牛:Java 的基本数据类型有 byte、short、int、long、float、double、char、boolean。 面试官:不错,回答得很准确。那 String 是基本数据类型吗? 王铁牛:不是,String 是引用数据类型,它是一个类。 面试官:很好。那说说 Java 中继承和多态的概念。 王铁牛:继承就是子类继承父类的属性和方法,多态就是同一个行为具有多个不同表现形式或形态的能力,比如父类引用指向子类对象。 面试官:回答得很清晰,基础很扎实。

第二轮面试 面试官:接下来聊聊 JUC 和多线程。什么是 JUC? 王铁牛:JUC 就是 java.util.concurrent 包,里面提供了很多并发编程的工具类。 面试官:那说说线程池有哪些常用的创建方式。 王铁牛:可以用 Executors 工具类创建,像 newFixedThreadPool、newCachedThreadPool 这些。 面试官:如果线程池的任务队列满了,新任务会怎样处理? 王铁牛:嗯……这个嘛,好像会有一些策略,具体我有点记不清了。 面试官:这里有几种拒绝策略,你下去可以再好好看看。那多线程中 synchronized 和 Lock 的区别是什么? 王铁牛:synchronized 是关键字,Lock 是接口,好像还有使用方式不太一样,其他的我就不太确定了。

第三轮面试 面试官:我们再谈谈一些框架和中间件。Spring 的 IOC 和 AOP 是什么? 王铁牛:IOC 是控制反转,就是把对象的创建和管理交给 Spring 容器;AOP 是面向切面编程,可以在不修改原有代码的基础上增加功能。 面试官:Spring Boot 有什么优点? 王铁牛:它可以快速搭建项目,简化配置,还内置了 Tomcat 等服务器。 面试官:MyBatis 中 #{} 和 ${} 的区别是什么? 王铁牛:这个……好像一个是预编译,一个不是,但具体哪个我有点乱了。 面试官:Dubbo 是做什么的? 王铁牛:Dubbo 好像是个分布式服务框架,但具体怎么用我不太清楚。 面试官:RabbitMQ、xxl - job、Redis 你都了解些什么? 王铁牛:RabbitMQ 是消息队列,xxl - job 是分布式任务调度平台,Redis 是缓存数据库,不过具体的细节我就说不太明白了。

面试官扶了扶眼镜,说道:“今天的面试就到这里,你整体对一些基础的 Java 知识掌握得还可以,但对于多线程、框架和中间件的一些细节问题回答得不够准确和深入。我们会综合评估你的表现,你回家等通知吧。”

问题答案

  1. Java 中基本数据类型有哪些? Java 的基本数据类型分为四类八种:
    • 整数类型:byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节)。
    • 浮点类型:float(4 字节)、double(8 字节)。
    • 字符类型:char(2 字节)。
    • 布尔类型:boolean(理论上 1 位,但实际实现通常是 1 字节)。
  2. String 是基本数据类型吗? String 不是基本数据类型,而是引用数据类型。它是 java.lang 包下的一个类,用于表示字符串。基本数据类型是 Java 语言预先定义的,而引用数据类型是通过类、接口等定义的。
  3. Java 中继承和多态的概念
    • 继承:是面向对象编程中的一种机制,子类可以继承父类的属性和方法,从而实现代码的复用和扩展。子类可以重写父类的方法,也可以添加自己的属性和方法。例如:
class Animal {
    void eat() {
        System.out.println("Animal is eating");
    }
}
class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dog is eating");
    }
}
- 多态:同一个行为具有多个不同表现形式或形态的能力。多态的实现有两种方式:方法重载和方法重写。方法重载是指在一个类中,有多个方法名相同但参数列表不同的方法;方法重写是指子类重写父类的方法。多态还可以通过父类引用指向子类对象来实现,例如上面的例子中可以这样使用:
Animal animal = new Dog();
animal.eat(); // 输出 Dog is eating
  1. 什么是 JUC? JUC 即 java.util.concurrent 包,是 Java 提供的用于并发编程的工具包。它包含了很多类和接口,例如线程池、锁、并发集合等,为开发人员提供了方便的并发编程解决方案。
  2. 线程池有哪些常用的创建方式?
    • Executors.newFixedThreadPool(int nThreads):创建一个固定大小的线程池,线程池中的线程数量始终保持为 nThreads。适用于需要控制并发线程数量的场景。
    • Executors.newCachedThreadPool():创建一个可缓存的线程池,如果线程池中的线程数量超过了处理任务所需的数量,空闲线程会在一段时间后被回收;如果有新的任务提交,线程池会创建新的线程来处理。适用于执行大量短期异步任务的场景。
    • Executors.newSingleThreadExecutor():创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。适用于需要保证任务顺序执行的场景。
    • Executors.newScheduledThreadPool(int corePoolSize):创建一个可定时执行任务的线程池,可用于执行定时任务或周期性任务。
  3. 如果线程池的任务队列满了,新任务会怎样处理? 线程池有四种拒绝策略:
    • AbortPolicy:默认的拒绝策略,直接抛出 RejectedExecutionException 异常,阻止系统正常运行。
    • CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务,从而降低新任务的提交速度。
    • DiscardPolicy:直接丢弃新任务,不做任何处理。
    • DiscardOldestPolicy:丢弃任务队列中最老的任务,然后尝试重新提交新任务。
  4. 多线程中 synchronized 和 Lock 的区别是什么?
    • 语法层面:synchronized 是 Java 中的关键字,是内置的语言实现;Lock 是一个接口,需要通过实现类来使用,例如 ReentrantLock。
    • 使用方式:synchronized 可以修饰方法和代码块,当修饰方法时,锁的是当前对象;当修饰静态方法时,锁的是当前类的 Class 对象。使用 Lock 需要手动加锁和解锁,一般在 try 块前调用 lock() 方法加锁,在 finally 块中调用 unlock() 方法解锁,以确保锁一定会被释放。
    • 锁的特性:synchronized 是可重入、非公平、不可中断的锁;Lock 可以实现可重入、公平、可中断的锁,通过构造函数可以指定是否为公平锁,还可以通过 lockInterruptibly() 方法实现可中断的锁。
    • 性能方面:在 JDK 1.6 之前,synchronized 的性能较差,JDK 1.6 之后对 synchronized 进行了优化,性能有了很大提升。在竞争不激烈的情况下,二者性能差不多;在竞争激烈的情况下,Lock 的性能可能会更好。
  5. Spring 的 IOC 和 AOP 是什么?
    • IOC(控制反转):是一种设计思想,将对象的创建和管理交给 Spring 容器,而不是由对象自己来创建和管理。通过依赖注入(DI)的方式,将对象之间的依赖关系注入到对象中,从而降低了对象之间的耦合度。例如,在 Spring 中可以通过 XML 配置、注解等方式将依赖注入到对象中。
    • AOP(面向切面编程):是一种编程范式,它允许在不修改原有代码的基础上,对程序的功能进行增强。AOP 通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,形成独立的切面,然后在合适的时机将切面织入到目标对象中。Spring AOP 支持基于代理的 AOP 实现,使用的是 JDK 动态代理和 CGLIB 代理。
  6. Spring Boot 有什么优点?
    • 快速搭建项目:Spring Boot 提供了很多启动器(Starters),可以快速集成各种依赖,减少了繁琐的配置过程。
    • 简化配置:Spring Boot 采用了约定大于配置的原则,很多配置都有默认值,开发者只需要在必要时进行少量的配置即可。
    • 内置服务器:Spring Boot 内置了 Tomcat、Jetty 等服务器,不需要手动部署到服务器中,直接运行应用程序即可。
    • 生产就绪特性:Spring Boot 提供了很多生产就绪的特性,如健康检查、监控等,方便开发者进行应用程序的管理和维护。
  7. MyBatis 中 #{} 和 ${} 的区别是什么?
    • #{}:是预编译处理,MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为占位符 ?,然后使用 PreparedStatement 进行预编译,这样可以防止 SQL 注入攻击。例如:
<select id="selectUserById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>
- **${}**:是字符串替换,MyBatis 在处理 ${} 时,会直接将 ${} 替换为实际的值,不会进行预编译,因此可能会存在 SQL 注入的风险。通常用于动态表名、排序字段等场景。例如:
<select id="selectUserByTableName" parameterType="String" resultType="User">
    SELECT * FROM ${tableName}
</select>
  1. Dubbo 是做什么的? Dubbo 是阿里巴巴开源的分布式服务框架,它提供了高性能和透明化的远程服务调用方案,以及服务治理方案。Dubbo 可以帮助开发者实现服务的注册与发现、负载均衡、集群容错、服务监控等功能,适用于大规模分布式系统的开发。通过 Dubbo,不同的服务可以分布在不同的服务器上,通过网络进行通信,实现服务的解耦和复用。
  2. RabbitMQ、xxl - job、Redis 你都了解些什么?
    • RabbitMQ:是一个开源的消息队列中间件,基于 AMQP(高级消息队列协议)实现。它可以实现异步通信、解耦、流量削峰等功能。生产者将消息发送到 RabbitMQ 的交换器(Exchange),交换器根据路由规则将消息路由到不同的队列(Queue),消费者从队列中获取消息进行处理。
    • xxl - job:是一个分布式任务调度平台,它提供了简单易用的任务调度功能,支持任务的动态添加、修改、删除,支持任务的分片、失败重试等。xxl - job 可以将任务分布到不同的节点上执行,提高了任务处理的效率和可靠性。
    • Redis:是一个开源的高性能键值对存储数据库,它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。Redis 通常被用作缓存、消息队列、分布式锁等,它可以将数据存储在内存中,读写速度非常快,同时还支持数据的持久化,以防止数据丢失。