Java核心基础高频考点

集合框架深度解析

在Java EE面试题中,集合框架是必问环节。面试官常追问HashMap的底层实现原理,特别是在JDK 1.8之后引入了红黑树以解决哈希冲突导致的性能下降问题。需要掌握HashMap与HashTable的区别,前者线程不安全但效率高,支持null键值;后者线程安全但性能较低。此外,ConcurrentHashMap在并发环境下的分段锁(JDK 1.7)和CAS+synchronized(JDK 1.8)机制也是考察重点。

多线程与并发编程

并发编程是区分初级与高级Java开发者的关键。核心考点包括ThreadLocal的内存泄漏问题及其使用场景,ThreadPoolExecutor的7大参数配置及拒绝策略,以及volatile关键字的可见性与禁止指令重排序特性。理解AQS(AbstractQueuedSynchronizer)底层原理,如ReentrantLock和CountDownLatch的实现机制,能显著提升面试竞争力。

反射、注解与动态代理

Spring框架的底层 heavily 依赖反射和动态代理。面试中常要求手写一个简单的DI容器或AOP实现。需掌握类加载机制(双亲委派模型),以及如何通过java.lang.reflect包获取类信息。动态代理分为JDK动态代理(基于接口)和CGLIB(基于继承),理解其在Spring AOP中的应用场景至关重要。

主流框架Spring Boot核心机制

Spring Bean生命周期
自动装配原理
MyBatis缓存机制

Spring Bean的生命周期详解

Spring Bean的生命周期是面试中的经典问题。整个过程可以概括为以下几个阶段:

  1. 实例化(Instantiation):Spring容器通过构造器或工厂方法创建Bean实例。
  2. 属性赋值(Populate):注入Bean依赖的属性,处理@Value和@Autowired注解。
  3. 初始化(Initialization):
    • 如果Bean实现了BeanNameAware,调用setBeanName()。
    • 如果Bean实现了BeanFactoryAware,调用setBeanFactory()。
    • 执行BeanPostProcessor.postProcessBeforeInitialization()。
    • 如果Bean实现了InitializingBean,调用afterPropertiesSet()。
    • 执行自定义的init-method。
    • 执行BeanPostProcessor.postProcessAfterInitialization()(AOP代理通常在此步生成)。
  4. 销毁(Destruction):容器关闭时,如果Bean实现了DisposableBean,调用destroy(),或执行自定义destroy-method。

Spring Boot自动装配原理

Spring Boot的核心在于“约定优于配置”。其自动装配主要通过@SpringBootApplication注解实现,该注解包含了@EnableAutoConfiguration。启动时,Spring Boot会扫描META-INF/spring.factories(或新版的org.springframework.boot.autoconfigure.AutoConfiguration.imports)文件,加载所有候选的自动配置类。通过@ConditionalOnClass、@ConditionalOnMissingBean等条件注解,判断是否满足配置条件,从而决定是否将Bean注册到IOC容器中。例如,当classpath下存在DataSource类且用户未手动配置时,自动配置类会自动创建嵌入式数据库连接池。

MyBatis一级与二级缓存

MyBatis提供了一级缓存和二级缓存。一级缓存是SqlSession级别的,默认开启,基于PerpetualCache的HashMap本地缓存,其作用域是SqlSession。当执行update、delete、insert操作时,会清空缓存。二级缓存是Mapper(Namespace)级别的,需要手动开启,基于Cache接口实现,默认使用PerpetualCache。二级缓存需要实体类实现Serializable接口。在实际企业级开发中,通常禁用MyBatis二级缓存,转而使用Redis等分布式缓存,以保证数据一致性。

JVM内存模型与调优实战

内存区域划分

JVM内存主要分为堆(Heap)和非堆(Non-Heap)。堆是GC的主要区域,分为新生代(Young Gen)和老年代(Old Gen)。新生代又分为Eden区和两个Survivor区(S0, S1)。非堆区包括方法区(Method Area,JDK8后为元空间Metaspace)和直接内存(Direct Memory)。

垃圾回收算法

常见的GC算法有标记-清除(Mark-Sweep)、标记-复制(Mark-Copy)和标记-整理(Mark-Compact)。新生代通常使用标记-复制算法,老年代使用标记-整理或标记-清除。G1 GC和ZGC是较新的收集器,旨在提供低延迟的垃圾回收体验。

常见OOM问题排查

OutOfMemoryError(OOM)常见原因包括:内存泄漏、堆空间不足、元空间不足、直接内存溢出。排查工具包括jmap(dump内存)、jstat(监控GC状态)、VisualVM(图形化分析)以及MAT(Memory Analyzer Tool)分析Dump文件,定位大对象和引用链。

MySQL数据库优化与Redis缓存

优化维度 关键策略 详细说明
索引优化 最左前缀法则 联合索引中,查询条件必须从索引的最左列开始,否则索引失效。
SQL语句 避免SELECT 只查询需要的字段,减少网络传输和内存消耗,利于覆盖索引。
分页查询 延迟关联 对于深分页(LIMIT 1000000, 10),先通过子查询获取ID,再关联查询详情,减少回表操作。
Redis缓存 缓存穿透/击穿/雪崩 穿透:查询不存在的数据,使用布隆过滤器或缓存空值;击穿:热点Key过期,使用互斥锁;雪崩:大量Key同时过期,设置随机过期时间。
Redis数据结构 适用场景 String(计数器)、List(消息队列)、Set(交集/并集)、ZSet(排行榜)、Hash(对象存储)。

微服务架构与分布式事务

Spring Cloud组件生态

微服务架构中,服务注册与发现通常使用Nacos或Eureka(已停更)。服务间调用使用OpenFeign,负载均衡使用Ribbon或LoadBalancer。网关层使用Spring Cloud Gateway进行路由转发和权限校验。配置中心使用Nacos Config或Spring Cloud Config实现配置动态刷新。

分布式事务解决方案

在微服务环境下,保证数据一致性是难点。常见方案有:
1. 2PC(两阶段提交):强一致性,但性能差,阻塞性强。
2. TCC(Try-Confirm-Cancel):应用层补偿,性能好,但代码侵入性强。
3. 本地消息表/MQ事务消息:最终一致性,基于消息队列实现,解耦性好,推荐使用RocketMQ的事务消息。
4. Seata:阿里开源的分布式事务框架,支持AT、TCC、Saga等模式。

服务熔断与限流

为了防止雪崩效应,需要使用熔断降级机制。Hystrix和Sentinel是主流组件。当服务提供者响应超时或异常比例超过阈值时,熔断器打开,快速失败。限流算法包括计数器、令牌桶和漏桶算法。Sentinel支持基于QPS、线程数的限流,以及热点参数限流。

实战代码:单例模式的双重检查锁

在Java EE面试题中,单例模式的线程安全实现是高频考点。以下是标准的DCL(Double-Checked Locking)实现:

public class Singleton {
    // volatile保证可见性,禁止指令重排序
    private static volatile Singleton instance;
    private Singleton() {
        // 私有构造器,防止外部实例化
    }
    public static Singleton getInstance() {
        // 第一次检查,避免不必要的同步
        if (instance == null) {
            synchronized (Singleton.class) {
                // 第二次检查,确保线程安全
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

解析:关键字volatile在这里至关重要。因为new Singleton()不是原子操作,它包括分配内存、初始化对象、设置引用指向内存地址三个步骤。如果没有volatile,可能发生指令重排序,导致其他线程获取到未完全初始化的对象,引发空指针异常或数据不一致。