《互联网大厂Java求职者面试:核心知识大考验》

53 阅读6分钟

面试官:请简要介绍一下 Java 中的多线程。

王铁牛:多线程就是一个程序里可以同时运行多个线程呗。

面试官:那线程池的作用是什么?

王铁牛:能复用线程,提高性能,减少创建和销毁线程的开销。

面试官:在高并发场景下,如何合理配置线程池参数?

王铁牛:呃,这个得根据任务类型和系统负载来调吧,我不太确定具体怎么弄。

第一轮提问结束。

面试官:说说 HashMap 的底层实现原理。

王铁牛:它是基于数组和链表实现的,还有红黑树,用来提高查找效率。

面试官:当 HashMap 发生哈希冲突时,会怎么处理?

王铁牛:会形成链表或者红黑树来存储冲突的元素。

面试官:如何优化 HashMap 的性能?

王铁牛:这个,我觉得可以调大初始容量啥的,具体不太清楚。

第二轮提问结束。

面试官:讲讲 Spring 的核心特性。

王铁牛:依赖注入、面向切面编程这些吧。

面试官:Spring Boot 自动配置的原理是什么?

王铁牛:不太明白,好像是根据一些条件自动配置一些组件。

面试官:如何在 Spring Boot 中集成 MyBatis?

王铁牛:呃,得加依赖,配置 XML 文件,好像是这样,具体细节记不清了。

第三轮提问结束。

面试官:今天的面试就到这里,我们会在一周内通知你面试结果,请回家耐心等待。

答案:

  1. 多线程:多线程是指在一个程序中可以同时运行多个线程。每个线程都有自己独立的执行路径,可以并发执行任务,从而提高程序的执行效率和响应速度。多线程可以通过继承 Thread 类或实现 Runnable 接口来创建,使用 start() 方法启动线程。线程之间可以通过共享内存、使用同步机制(如 synchronized 关键字)来协调访问共享资源,避免数据竞争和不一致问题。同时,还可以使用线程池来管理和复用线程,提高线程的创建和销毁效率。
  2. 线程池:线程池的作用主要有以下几点:
    • 复用线程:避免频繁创建和销毁线程,减少系统开销。
    • 提高性能:线程池中的线程可以被重复使用,快速响应任务请求。
    • 便于管理:可以统一管理线程资源,设置线程的最大数量、核心线程数、队列容量等参数,以适应不同的业务场景。
    • 控制并发度:通过控制线程池中的线程数量,避免过多线程同时执行导致系统资源耗尽或性能下降。
  3. HashMap 底层实现原理
    • 数组 + 链表/红黑树:HashMap 内部维护一个数组,数组的每个元素是一个链表节点(JDK 1.8 之前)或红黑树节点(JDK 1.8 及之后)。
    • 哈希函数:通过对 key 进行哈希计算,得到一个哈希值,然后根据哈希值确定元素在数组中的位置。
    • 哈希冲突处理:当两个或多个 key 的哈希值相同,就会发生哈希冲突。在 JDK 1.8 之前,冲突的元素会形成链表,新元素添加到链表头部;在 JDK 1.8 及之后,当链表长度超过 8 且数组容量大于等于 64 时,链表会转换为红黑树,以提高查找效率。
    • 扩容机制:当 HashMap 中的元素数量超过数组容量 * 负载因子(默认 0.75)时,会进行扩容。扩容时,会创建一个新的更大的数组,将原数组中的元素重新计算哈希值后放入新数组中。
  4. Spring 核心特性
    • 依赖注入(Dependency Injection):通过控制反转(IoC)容器,将对象之间的依赖关系由程序代码直接控制转换为由容器来管理。容器根据配置文件或注解,将依赖对象注入到需要的地方,降低了对象之间的耦合度。
    • 面向切面编程(Aspect Oriented Programming,AOP):允许将一些通用的功能(如日志记录、事务管理等)从业务逻辑中分离出来,以切面的形式进行统一处理。通过 AOP,可以在不修改原有业务代码的情况下,增强系统的功能和可维护性。
    • IoC 容器:负责创建、管理和装配对象,维护对象之间的依赖关系。常见的 IoC 容器实现有 Spring 容器,它通过 XML 配置文件、Java 配置类或注解来定义对象的创建和依赖关系。
    • 事务管理:Spring 提供了强大的事务管理功能,支持声明式事务和编程式事务。声明式事务通过注解或 XML 配置,方便地将业务方法纳入事务管理,使得事务处理与业务逻辑分离,提高了代码的可读性和可维护性。
  5. Spring Boot 自动配置原理
    • 条件配置:Spring Boot 根据项目中引入的依赖和配置信息,自动判断应用的环境和需求。通过一系列的条件注解(如 @ConditionalOnClass、@ConditionalOnMissingBean 等),来决定是否配置某个组件或功能。
    • 自动配置类:Spring Boot 提供了大量的自动配置类,这些类定义了各种组件的默认配置。当应用启动时,Spring 会根据条件判断,自动加载符合条件的自动配置类,并将相关的 Bean 注册到容器中。
    • 属性绑定:自动配置类会读取 application.properties 或 application.yml 中的配置属性,并将其绑定到相应的组件或配置对象上。这样,开发者可以通过修改配置文件来定制应用的行为,而不需要修改大量的代码。
    • 约定大于配置:Spring Boot 遵循约定大于配置的原则,通过默认的配置和约定,减少了开发者的配置工作量,使得应用的开发和部署更加简单快捷。
  6. 在 Spring Boot 中集成 MyBatis
    • 添加依赖:在项目的 pom.xml 文件中添加 MyBatis 和 MyBatis Spring Boot Starter 的依赖。
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>最新版本</version>
    </dependency>
    
    • 配置数据源:在 application.properties 或 application.yml 中配置数据库连接信息,如数据库驱动、URL、用户名、密码等。
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/yourdb
    spring.datasource.username=root
    spring.datasource.password=password
    
    • 配置 MyBatis:创建 MyBatis 的配置类,在类上使用 @MapperScan 注解扫描 Mapper 接口所在的包。
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @MapperScan("com.example.mapper")
    public class MyBatisConfig {
    }
    
    • 编写 Mapper 接口和 XML 文件:创建 Mapper 接口,定义数据库操作方法,并编写对应的 XML 文件,实现 SQL 语句。
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    
    @Mapper
    public interface UserMapper {
        @Select("SELECT * FROM user WHERE id = #{id}")
        User getUserById(Integer id);
    }
    
    • 使用 Mapper:在 Service 或其他需要的地方注入 Mapper 接口,调用接口方法进行数据库操作。
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
    
        @Autowired
        private UserMapper userMapper;
    
        public User getUserById(Integer id) {
            return userMapper.getUserById(id);
        }
    }
    

通过以上步骤,就可以在 Spring Boot 项目中集成 MyBatis,实现数据库操作。