ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

准备Java面试,我梳理了这些核心知识点

准备Java面试,我梳理了这些核心知识点 Java面试的核心知识点从来不是一张API清单。很多人背了上百道题结果面试官一句“你讲讲ArrayList和LinkedList的区别”就能让他卡壳——因为区别本身只值三秒钟真正值钱的是为什么会有这种区别以及这种区别在真实系统中如何主导你的选型。面试官想看到的是你对技术本质的拆解能力而不是记忆复现能力。集合框架不是背区别是理解数据结构背后的权衡ArrayList和LinkedList的区别你当然可以说出“数组 vs 链表”“随机访问快 vs 插入删除快”。但这只是开始。真正深入的问题是LinkedList在Java里几乎是一个“失败的设计”因为它的每个节点需要额外存储前后指针内存占用翻倍而且CPU缓存不友好实际遍历性能远低于ArrayList。所以你写代码时如果只是“频繁增删”就选LinkedList那大概率是错的——你应该用ArrayDeque或者CopyOnWriteArrayList。面试官真正想听的是你知不知道理论复杂度与工程性能是两回事。再比如HashMap。你知道它底层是数组加链表加红黑树知道扩容因子是0.75但你知道为什么是0.75而不是0.5或1.0吗这是空间与时间的平衡点。0.75意味着在绝大多数场景下哈希冲突的概率与浪费空间的比例都控制在可接受范围。更深一层你知道为什么链表转红黑树的阈值是8而红黑树转链表是6吗这背后是泊松分布的统计结论在随机哈希函数下链表长度达到8的概率已经低于千万分之一。如果你能从这个层面解释面试官眼中你不再是背诵者而是理解者。JVM面试必考但很多人只背了参数JVM的知识点像一座冰山面试官永远只露出一个角内存区域、GC算法、类加载机制。但真正的深水区在于——你能不能在纸上画出你的系统在某个瞬间的内存分布状态比如线上OOM了你的第一反应是什么不是去看GCRoots而是先看堆转储看是哪个对象占了大头。但在这之前你得知道JVM默认的垃圾收集器在JDK8是Parallel Scavenge加Parallel Old在JDK11是G1这直接决定了你调优的方向完全不同。很多人背了CMS和G1的区别却没想过为什么G1要设计成Region化。因为CMS的并发标记需要扫描整个老年代而G1把堆分成多个Region每次只回收收益最大的Region集合这样停顿时间就可预测了。但这又带来新问题Region间的对象引用怎么处理于是就有了Remembered Set。你看知识是一环扣一环的面试官只要顺着一个点往下追立刻就能分辨你是真懂还是背题。并发核心不在API在于“可见性”和“有序性”的博弈Java并发最常考的是synchronized和ReentrantLock的区别volatile的语义线程池的参数。但真正的分水岭在于你是否理解并发问题的根源是三件事原子性、可见性、有序性。synchronized能同时解决三者volatile只能解决可见性和有序性不能解决原子性。这个基础如果扎实很多问题就迎刃而解。比如你写了一个双重检查锁的单例为什么要加volatile因为synchronized只能保证原子性和可见性不能保证重排序对另一个线程的“半初始化”状态可见。new一个对象有三个步骤分配内存、初始化、赋值引用CPU和编译器可能重排成“分配内存、赋值引用、初始化”。如果没有volatile的写屏障另一个线程可能看到引用不为null但对象还没构造完成。这就是经典的DCL失效问题。你能把这个故事讲清楚比背十道并发面试题都管用。线程池也是重灾区。很多人背了核心线程数、最大线程数、队列长度、拒绝策略但面试官一问“你的核心线程数怎么定”就哑了。线程池的大小不是拍脑袋而是跟任务类型强相关CPU密集型任务线程数约等于CPU核心数IO密集型任务线程数可以设置为核心数乘以(1平均等待时间/平均计算时间)。更进阶的是你要知道线程池里的线程创建是懒加载的只有当提交任务数超过核心线程数时才开始进入队列。如果你理解了这个机制就会明白为什么当系统突发流量时线程池的吞吐会先平滑上升而不是瞬间打满。数据库索引的本质是数据组织方式MySQL面试几乎绕不开索引。但很多人只背了“B树索引适合范围查询”“最左前缀原理”。更深一层你要理解为什么InnoDB选择B树而不是B树或红黑树。B树的所有数据都存在叶子节点并且叶子之间通过链表相连这样范围查询只需要遍历链表而不需要回树中做中序遍历。而红黑树是二叉树高度远高于B树磁盘IO次数更多。索引的本质是减少磁盘IO次数而B树的高度通常只有3到4层意味着最多3到4次IO就能定位到目标行。另一个高频考点是事务隔离级别。你能背出四个隔离级别但你能解释“为什么MySQL默认使用可重复读而Oracle默认使用读已提交”吗因为MySQL的binlog在Statement格式下如果使用读已提交可能出现主从数据不一致。这个历史包袱让MySQL的默认级别变得很保守。面试官问这个其实是想看你对数据库设计取舍的敏感度。再看一个实战问题慢SQL怎么优化很多人说“加索引”。但加索引不是万能的尤其是如果已经加了索引还慢那问题多半出在查询写法上。比如你对索引列进行了函数运算会导致索引失效你用了select导致回表成本高你通过or连接非索引列可能全表扫描。更隐蔽的是隐式类型转换如果字段是varchar你传入intMySQL会先把字段转成数字再对比这样索引完全失效。这些细节才是面试官想听到的“实战经验”。Redis不只是缓存是分布式系统的粘合剂Redis在Java面试中几乎每面必问。但很多人只停留在“缓存穿透、缓存击穿、缓存雪崩”这三种经典问题。我建议你抛开这些“八股”去思考一个更底层的问题Redis为什么快单线程模型、IO多路复用、纯内存操作、高效的数据结构这些都对但核心在于Redis把所有操作都放在一个线程里避免了线程切换和锁竞争的开销。而你在用Redis的时候是否意识到你要尽量避免执行耗时命令比如KEYS因为它会阻塞整个事件循环这就是所谓“慢查询”的根源。谈到分布式锁很多人会用SETNX加EXPIRE但你知道这样会存在“锁过期但业务还没执行完”的隐患吗Redisson的看门狗机制就是来解决这个问题的给锁自动续期直到业务完成。更深一层真实的生产环境里你还要考虑主从切换导致锁丢失的问题此时你需要RedLock但RedLock本身又有争议。面试官并不期待你能给出完美方案而是想看你是否能清晰地分析各种方案的权衡。Spring与Spring Boot控制反转不是魔法是设计模式Spring是Java后端面试的“家常菜”。核心考点包括IOC、AOP、Bean生命周期、事务传播行为。但很多人的理解只停留在“IOC就是把对象创建交给容器”这句话。你要深入一层IOC容器本质上是一个基于反射的工厂模式它通过扫描注解或XML配置将类的实例化过程集中管理从而解耦了对象之间的依赖关系。当你写Autowired时面试官可以追问如果同类型有多个Bean怎么办你可以说用Qualifier指定名字但更进一步你能否解释为什么Spring在默认情况下Bean是单例的因为单例避免了重复创建的性能开销但单例也有线程安全问题——Spring中的Controller默认是单例的所以你要保证Controller里不能有可修改的实例变量。AOP的考点更偏向“动态代理”。你要清楚Spring AOP默认使用JDK动态代理基于接口还是CGLIB基于继承在Spring Boot 2.x以后默认采用CGLIB代理因为优先支持类代理而不是接口代理。但你有没有想过CGLIB代理是通过生成子类来实现的所以被代理的类不能被final修饰。这些细节有时候比理论本身更有区分度。事务传播行为也是高频点。比如REQUIRES_NEW和NESTED的区别——前者是挂起当前事务开启一个完全独立的新事务后者是当前事务里保存一个保存点如果内层事务回滚不影响外层事务的主流程。但更重要的一个坑是在同一个类中的方法之间调用事务注解会失效因为Spring的事务是通过AOP代理实现的内部调用不会经过代理。你能指出这个坑面试官就知道你踩过坑。分布式与微服务别只背CAP要讲出取舍分布式面试绕不开CAP理论。但CAP不是三选二而是在分区P发生的时候你必须在一致性和可用性之间做选择。大多数互联网场景都会选择AP比如注册中心Eureka、Nacos的临时实例模式而ZooKeeper是CP。但你真到业务里比如订单库存扣减你更希望是强一致还是最终一致答案往往是最终一致加补偿机制。分布式事务的最终方案是由业务驱动而不是由技术驱动所以你回答这个问题时应该结合具体的业务场景是下单、是支付、还是物流状态更新每个场景的容错性都不同。消息队列的面试点也很多。你可以说Kafka的优势是吞吐量高RocketMQ的优势是事务消息和延迟消息。但面试官更可能问如何保证消息不丢失如何保证消息不重复消费这是两个对立的问题——不丢失需要确认机制和持久化不重复需要幂等设计。你会看到在分布式系统里没有完美方案只有用幂等性来对冲重复用重试机制来对冲丢失。这种“权衡”思维才是面试官最看重的。设计模式与代码功底洗掉“面试味”很多候选人对设计模式只背个“单例、工厂、策略、模板”但面试官其实想知道的是你有没有在真实项目里用设计模式解决过“坏味道”比如如果你说用策略模式替代了多个if-else面试官肯定会追问策略对象怎么管理是用Map还是Spring容器如果你能答出“用Spring注入一个MapString, Strategykey就是策略类型”那这就非常落地。另外开闭原则不是让你拼命写抽象类而是让新功能的添加不修改旧代码。如果你能用“模板方法模式回调”来设计一段业务编排这就是加分项。再说到数据结构和算法。Java面试中算法题往往只考热门的二叉树遍历、链表反转、TopK、LRU缓存。但你要记住面试官不是考你算法本身而是考你的调试和推导能力。你就题论题写一个答案不如把你思考过程说出来“我想到用双指针因为这样可以做到O(n)时间、O(1)空间”“这里的边界条件要注意链表长度为1的情况”。这种表达比闷头写代码强得多。简历上没有的“加分项”思考深度与好奇心最后我要说一个容易被忽略的点。决定面试成败的往往不是知识点本身而是你如何组织知识的关系。你能画出从HashMap到ConcurrentHashMap的演进过程并且解释为什么ConcurrentHashMap在JDK8放弃分段锁而改用CAS加synchronized——因为分段锁的内存开销太大而synchronized在JDK6之后进行了锁升级优化性能已经不输ReentrantLock。如果你的知识是网状的每个点都能跟其他点连起来那面试官就追不住你。反之如果每个知识点都是孤岛他就随便找一个海沟把你淹了。准备Java面试不要追求“覆盖了多少题”而要追求“理解了多少条原理”。当你把volatile、synchronized、CAS、AQS、线程池、JMM这一串名词串成一条线你会猛然发现它们都在讲同一件事如何管理共享状态。同样当你能把索引、事务隔离级别、binlog、Spring事务传播放在一起思考你会发现它们都在处理“一致性”这个主题。面试的本质不是考察记忆的广度而是考察认知的深度。你可以答不上来某个冷门API的签名但你不能说不清自己项目里为什么用Redis而不用本地缓存——因为那一次的选择才真正定义了你的水平。所以别急着刷题目录。先拿起你手边的源码看看HashMap的红黑树结构翻翻JVM的垃圾收集器日志写个小的并发程序跑一下。真正的面试准备是从你第一次对“为什么”产生怀疑开始的。而当你把这些“为什么”都内化成自己的语言你站在面试官面前就不再是背诵者而是一个真正的工程师。
返回列表