尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Java技术八股Day23:面向对象、策略模式、动态代理与数据一致性解析

发布时间:2026/9/24 23:40:55

资讯中心
01
ARTICLE

Java技术八股Day23:面向对象、策略模式、动态代理与数据一致性解析

Java技术八股Day23:面向对象、策略模式、动态代理与数据一致性解析
1. 今日复盘Java技术八股学习Day23的定位与内容规划Java技术八股说直白点就是Java面试中反复出现的高频知识点与经典题目合集。我在坚持这套系列学习笔记时每天都会固定抽出两到三个小时把当天要啃的知识点拆成题目原理应用场景延伸追问四层Day23这天的内容正好处在整个知识体系的中后段这时候基础语法、集合、并发、JVM这些大块头已经过完一遍剩下的重点是那些容易被面试官往深里挖的设计模式、动态代理、数据一致性这类偏工程和架构思维的题目。熟悉我学习节奏的朋友都知道Day23这个编号在完整的Java技术八股学习路线里并不是一个孤立章节它是承前启后的一个节点。前面的Day15到Day20一直在做Java基础、面向对象特性、常见集合源码分析从Day22开始转入设计模式与框架底层原理的结合Day23顺着这条线继续往策略模式、动态代理和一致性保障方向走正好能把怎么写好Java代码和怎么让Java代码在真实项目中稳定运行这两件事串起来。对于正在准备Java面试的朋友Day23的内容非常适合用来检验自己到底有没有把基础学扎实。很多人在背八股时容易陷入一个误区就是只记结论不追原因比如知道JDK动态代理要基于接口、CGLIB可以代理类但说不清楚为什么会有这个区别也举不出生产环境里的实际案例。Day23的规划重点就是围绕这个问题展开我刻意把题目整理成如果面试官追问三连你要能接得住的标准每个知识点都至少准备一层源码级的理解作为底牌。这一天的学习目标我定得很明确四个核心主题面向对象里的继承与多态、策略模式与组合复用、动态代理的JDK与CGLIB差异、本地事务到分布式事务的一致性保障思路。这四个主题表面上看是分散的零碎知识点实际指向的都是同一个底层能力就是用抽象思维组织代码用工程思维保障系统。下面我把每个主题的拆解过程和实操要点完整记录下来希望对自学Java、准备面试的朋友有帮助。2. 面向对象核心题继承、封装、多态的八股追问拆解2.1 三个特性的本质与常见误解面向对象是Java的根面试官几乎不会直接问什么是面向对象而是通过具体场景考你对三大特性的理解深度。我复习Day23时整理了一套自问自答的清单封装解决的是谁可以改我的数据继承解决的是如何复用已有代码多态解决的是如何让同一段代码处理不同类型的对象。很多教材把继承放在第一位介绍但真正动手设计时封装才是面向对象的第一原则先把数据和行为绑在一起再考虑怎样抽象出父类。Java技术八股里常考的陷阱是继承破坏了封装。我刚开始觉得这句话有点绕后来结合源码看才明白父类一旦公开了protected方法或者可变字段子类就可能无意中影响父类的内部状态。举个实际例子父类的构造函数里调用了一个可被重写的方法子类在重写时又用到了子类自己还没初始化完成的字段这种情况在项目里排查起来非常痛苦。归根到底面向对象不是简单地把类写出来而是要控制好信息的能见度。关于多态最常见的追问是重载和重写的区别。这题看起来简单但至少有五个层次可以挖第一层是定义区别第二层是编译期与运行期的绑定时机第三层是返回值是否算方法签名第四层是父类引用指向子类对象的访问范围第五层是静态方法能不能被重写。我在Day23笔记里把官方标准表述和源码验证结合着看发现最有用的记忆方式是用一句口诀重载是静态的、看参数重写是动态的、看对象。2.2 从String到equals与hashCode的经典组合题面向对象话题往下延伸几乎必然要碰到equals和hashCode这套组合题。Java面试不把这两个方法问清楚的很少常见问法是重写equals为什么必须重写hashCode。我第一次背八股时直接记结论后来在项目里真踩了一次HashMap的坑才彻底理解当你把一个对象当作key放进HashMap如果只重写equals不重写hashCode那么相同内容的两个对象会计算出不同的hash值导致HashMap认为它们是两个不同的key不仅取不到数据还会越存越多。我建议学习时自己写一段小代码验证这个结论。你定义一个只有id字段的Person类只重写equals不重写hashCode然后创建两个id相同的对象分别作为key放进HashMap第二次put的时候你会发现集合里出现了两个几乎一样的元素。这个实验十分钟就能完成但比看十篇博客记忆都深刻。另一个方向是String自身的equals设计。String重写了equals和hashCode所以在使用String做Map的key时不用担心内容相同但引用不同的问题。但面试官经常会继续追问String和new String的区别String为什么是不可变的这类延伸题建议把字符串常量池、不可变性的好处、输入法般的字符拼接性能问题放在一起复习。2.3 接口与抽象类到底该怎么选接口和抽象类的区别属于Java基础面试题里的常青树Day23计划里排在面向对象板块的压轴位置。总结起来可以分成五个维度设计理念上抽象类是是什么的关系接口是能干什么的关系继承限制上一个类只能继承一个抽象类但可以实现多个接口成员变量上抽象类可以有实例变量接口里的变量隐式是public static final方法上抽象类可以有具体方法接口在Java 8之后才支持default和static方法语义上抽象类捕获子类的共性接口定义实现者的契约。不过单纯背区别还不够面试官容易继续追问什么时候优先用接口。我在实际编码里的经验是如果你希望一组完全不相关的类都拥有某种能力比如都支持序列化、都支持比较大小那就用接口如果你希望把公共代码抽到基类里同时保留一定的模板方法那就用抽象类。还有一个工程上的小技巧Java 8之后接口的default方法可以用来做功能增强避免大规模改动实现类但也要注意别滥用否则接口会膨胀成一个什么都有的大杂烩。3. 策略模式与组合复用让代码告别if-else的实战拆解3.1 为什么面试官爱考策略模式设计模式里策略模式算是Java面试八股文的高频题原因在于它既好讲又贴近业务。我记得自己刚学设计模式时觉得策略模式不就是多态嘛后来在项目中负责过一个订单折扣计算的模块各种满减、会员折扣、限时促销叠在一起if-else写了七八层维护一次加一个需求就头大一次。后来重构时用策略模式把每一种计价方式抽成一个实现类主流程只剩下一个Dispatch那一刻才真正理解了策略模式的工程价值。策略模式的经典定义是定义一族算法让它们可以互相替换使得算法的变化独立于使用算法的客户端。拆开看就是三个角色Context上下文、Strategy抽象策略、ConcreteStrategy具体策略。对应到订单场景OrderService是ContextDiscountStrategy是接口满减、会员折扣、新人价分别是具体实现类。这样写的好处很直接新增一种促销方案时不需要改动已有的业务方法只要增加一个新的策略实现类符合开闭原则。3.2 用枚举和Map让策略注册更优雅常规的策略模式写法里Context中会持有Strategy的引用然后在构造方法或者setter里注入具体策略。但真实项目里策略往往不止一个更多时候需要根据某个类型码动态决定走哪个策略。这里我推荐一种在Java技术八股学习Day23里重点记录的组合玩法就是策略枚举 Map注册表。我把实现步骤整理出来供参考。第一步定义一个枚举类枚举项对应业务类型枚举里持有该类型对应的策略类实例这样类型和策略的映射关系就被集中管理起来。第二步在具体策略实现类上加上Spring的Component注解让它们成为Bean。第三步在某个配置类里把所有的策略实现注入到一个Map里key是类型码value是策略实例这样调用方只需要一行代码就能拿到正确策略。这么做的好处我在项目里体会很明显。首先消灭了switch-case或if-else的分支判断后面再加类型只是在枚举里多加一项、新增一个组件类不需要动核心逻辑。其次是每个策略类只做一件事配合小类名可读性比一大坨条件分支强太多。此外策略实现类之间天然隔离单测也更好写直接对某个策略类做单元测试即可。3.3 策略模式高概率追问与状态模式、工厂模式的区别背策略模式的时候不能只背定义否则问个变种就容易卡住。面试官经常把策略模式、状态模式、工厂模式放在一起问。我自己的理解是三个模式的关注点不同。工厂模式解决对象如何创建的问题调用方不关心具体类只要告诉工厂需要什么类型就能拿到对象。策略模式解决算法如何选择和替换的问题关注的是行为。状态模式解决对象状态变化时行为如何改变的问题状态本身会流转而策略一旦选定一般不会自动切换。还有一种追问是策略模式能否替代if-else。我的答案是能替代大部分但不必为了替代而替代。如果分支只有两三个、逻辑又很短直接if-else反而更直观引入策略模式反而增加类和文件数量。做技术决策要结合团队维护成本和代码规模八股给我们的是一种思路不是教条。还有一个值得注意的细节是策略模式接口里方法的设计。方法参数最好传一个统一的上下文对象而不是各传各的参数这样后续扩展字段时不用修改接口签名否则每次需求变更都要动到所有实现类维护成本直线上升。我当时设计订单折扣策略时就吃过这个亏后面统一改成OrderContext对象传参才真正稳定下来。4. 动态代理深度剖析JDK与CGLIB的底层实现差异4.1 动态代理到底解决了什么问题Java动态代理在面试题里的出现频率极高它是很多框架原理的基础像Spring AOP、MyBatis的Mapper接口、Feign的远程调用都依赖它。在Java技术八股学习Day23里我把动态代理放在策略模式之后学习因为两者的思想有联系代理的本质是不直接操作目标对象而是通过一个代理对象间接操作在代理对象里可以加额外的逻辑。静态代理其实很好理解就是手动写一个和目标类实现同一接口的代理类在调用目标方法前后做点事情。但静态代理的问题是每个目标类都要手写一个代理类类数量膨胀不说重复代码也多。动态代理的价值就体现在动态两个字上可以在运行时为任意接口生成代理对象不用为每个类单独写代理类。用一个我常打的比方动态代理就像给快递公司做代收。收件人不方便收件时快递可以放在代收点代收点在包裹签收前帮你检查外包装、登记信息代收点并不修改包裹内容。放到代码里目标方法就是那个包裹代理逻辑就是签收时额外做的检查和登记。4.2 JDK动态代理的实现要点与源码级理解JDK动态代理最核心的类是Proxy和InvocationHandler使用时有三个步骤。第一步让目标类实现至少一个接口。第二步定义InvocationHandler的匿名内部类或者单独实现类在invoke方法里写入增强逻辑。第三步通过Proxy.newProxyInstance方法创建代理对象参数分别是类加载器、目标类实现的接口数组、InvocationHandler实例。面试官如果追问newProxyInstance到底做了什么就要说到源码层面了。在JDK的实现里Proxy会从传入的接口数组中提取方法信息然后在运行时动态生成一个继承自Proxy并实现这些接口的代理类字节码再把代理类的Class对象返回。之后调用代理对象的任何接口方法时都会被分派到InvocationHandler的invoke方法里执行。这也解释了为什么JDK动态代理的前提是目标必须有接口因为生成的代理类是通过接口暴露方法的如果再让它继承一个具体的类Java的单一继承限制就不允许了。另外要注意invoke方法的三个参数的用途proxy是生成的代理对象自己method是当前被调用方法的Method对象args是方法入参。增强逻辑就写在method.invoke(target, args)之前或者之后。你可以在invoke里加日志、加权限校验、加事务控制这就是AOP的最基本原理。4.3 CGLIB代理的原理与选型建议CGLIB代理则走的是另一条路线。它不要求目标类实现接口因为它的原理是通过继承目标类来生成一个子类然后在子类里重写父类的方法在重写逻辑中插入增强代码。用CGLIB有一个很重要的限制就是目标类和方法不能被final修饰否则无法被继承或重写。这也是为什么Spring在配置Bean时如果发现目标类没有接口默认会切换成CGLIB来生成代理。CGLIB底层依赖ASM字节码操作框架生成子类时会对目标类的方法做拦截具体由MethodInterceptor接口配合Enhancer类来实现。使用上大致是这样创建Enhancer对象设置要代理的父类设置回调方法最后调用create方法生成代理对象。整个过程比JDK动态代理多了一些字节码操作的细节但在日常开发中大多数时候我们不会直接碰CGLIB的API而是通过Spring容器间接使用它。关于选型我在项目里的经验比较明确如果目标类有接口优先用JDK动态代理因为原生支持、代码简单、无额外依赖如果目标类没有接口比如某些Service实现类只写了一个具体类那就只能退回到CGLIB。Spring的ProxyFactory会自动做这种选择但面试时你得能说出两者的边界。4.4 动态代理的常见面试变种与避坑点动态代理这一块面试官很喜欢变着法考。一种问法是JDK动态代理和CGLIB动态代理的性能差异。从历史角度看JDK 8之前的版本里CGLIB因为底层直接操作字节码在某些场景下性能优于反射实现的JDK代理但JDK 8之后优化了反射调用两者差距已经很小现代框架更看重的是适用范围和代码的简洁程度。另一种问法是Spring AOP默认使用哪种代理这要看Spring版本Spring Boot 2.x之后默认使用CGLIB即使目标类有接口所以如果看到代理对象命名里带有CGLIB字样不用奇怪。还有一个实战中容易踩的坑就是使用动态代理时调用同类内部方法的增强失效问题。比如一个Service里methodA调用了同类里的methodBmethodB上有Transactional注解实际事务不生效。原因是在动态代理模式下外部调用走的是代理对象而methodA内部调用this.methodB时走的是目标对象的原始方法并没有经过代理。解决方案是注入自身的代理对象或者通过AopContext.currentProxy获取当前代理或者把methodB移到另一个Bean里。这种问题在八股里不常见但在真实项目里排查起来特别浪费时间建议学习时就记下来。5. 数据一致性从本地事务到分布式事务的关键场景5.1 数据一致性到底指什么数据一致性在Java后端面试里的地位越来越重要Day23把它放到学习计划中是为了与事务原理、并发控制、缓存策略形成一条线。数据一致性可以简单理解成多点数据之间始终能对上账。在单体应用里一致性由数据库的ACID事务来保障在微服务和分布式环境下多个服务、多个数据源之间的数据要想保持一致就比单体复杂得多。面试中一致性常以最终一致性和强一致性的区别来考。强一致性是指数据更新之后任何后续读取都能立即读到最新值最终一致性则允许有一个短暂的中间状态但经过一段时间后所有副本最终会收敛到同一状态。在实际业务里秒杀扣库存、转账、下单扣库存这类场景不容忍金额错误需要强一致性或者通过事务机制保证而像用户点赞数、阅读量这类数据短时间内的延迟是可以接受的更适合最终一致性的方案。5.2 本地事务中的隔离级别与并发一致性先看单体应用里的一致性保障。数据库提供的本地事务是Java后端的第一道防线而事务的ACID四个特性里面试官最常追问的就是隔离性。SQL标准定义了四个隔离级别读未提交、读已提交、可重复读、串行化。MySQL默认是可重复读Oracle默认是读已提交。不同级别对应不同的并发问题读未提交可能发生脏读读已提交解决了脏读但会出现不可重复读可重复读解决了不可重复读但可能出现幻读串行化性能损耗太大一般不作为常规选择。八股背到这里还不够最好能理解MySQL的MVCC机制如何支撑可重复读。MVCC就是多版本并发控制核心原理是在每一行记录中维护隐藏列存储创建版本号和过期版本号快照读操作通过版本号比较读取到符合当前事务可见性版本的记录。但要注意MVCC解决的是快照读场景下的可重复读如果当前读使用select for update或者update语句仍然可能产生幻读问题InnoDB通过间隙锁和Next-Key Lock来进一步防止范围插入导致的幻读。这块内容我在Day23的笔记里画了版本号示例图才彻底捋顺建议学习时也通过行版本示例自己推演一遍。5.3 分布式事务的常见方案对比进入分布式场景后本地事务就解决不了问题了。常见的分布式事务方案有XA两阶段提交、TCC、Saga、本地消息表和消息事务。每种方案都有适用场景和取舍。XA两阶段提交强调的是强一致性通过事务管理器协调多个资源管理器性能开销较大适用于并发不高的核心转账场景。TCC是补偿事务模式分为Try、Confirm、Cancel三个阶段需要业务方实现对应的接口对业务侵入较大但性能较高。Saga由一组本地事务组成每个步骤都可能执行补偿操作适合长事务场景。本地消息表方案我实际用过不少思路是把核心业务操作和消息写入放在同一个本地事务里利用数据库事务保证一致性然后通过定时任务把消息表里的消息发送到MQ消费方处理成功后回调确认。这种方案的缺点是需要额外维护消息表还会增加消息延迟但实现上较简单适合大部分最终一致性场景。RocketMQ的事务消息则把本地事务和消息发送合在一起发送半消息执行本地事务再根据结果提交或回滚确认消息底层原理跟本地消息表相似但把复杂度封装到了MQ里。5.4 从面试题到架构思考一致性多选题怎么答数据一致性相关的面试题往往不是孤立出现的更多是结合场景综合考察。题目里给一套未做优化的秒杀系统要求扣减库存不能超卖这类题背后考的是并发控制方案选型。单机上可以用synchronized、ReentrantLock这类JVM锁但集群环境必须依赖分布式锁比如Redis的SETNX加过期时间或者ZooKeeper的临时顺序节点。更优的方案是使用RedisLua脚本做原子扣减把判断库存和扣减库存放在一个Lua脚本里执行既减少网络开销又保证原子性。再比如下单后积分服务调用失败怎么办这类问题本质上考的就是分布式系统里的最终一致性设计。我通常会这样回答先保证主链路的下单事务提交成功把给用户加分这个动作转换成一条消息写入消息表返回用户下单成功后台定时任务或者MQ消费者读取消息执行积分变更如果执行失败就重试重试多次仍然失败时转入人工或告警。关键点是接受最终一致性避免因为一个非核心依赖的失败导致整个用户操作失败。Day23在一致性这块的核心感悟是背方案名称很容易难的是知道什么时候该用哪个。面试时如果能主动说出强一致性会带来系统可用性的下降我们业务对金额敏感所以选TCC而积分这类允许延迟的就用消息表这类表达远比机械罗列方案名称更能体现你的架构思维。6. 八股学习路线与复盘方法让Java面试准备真正有效6.1 我的Day23笔记复盘哪些题容易答不透每次学完一天的内容我都会花二十分钟做一个简单的复盘把今天整理的题目分成三类能直接答出标准定义的、能讲清原理并举例的、感觉自己还没掌握透的。Day23结束后的复盘结果是面向对象和策略模式掌握得比较扎实动态代理的理解在画过类结构图后也有明显提升最难的是数据一致性与事务的交叉题因为它要求同时熟悉SQL事务机制、应用层并发控制和分布式协议经常会有知道每个点但串不到一起的感觉。应对串不到一起这个问题的办法我会做一套自己的知识卡片或者思维导图。不是简单地复制题目和答案而是把每个知识点当作一个节点把相关联的知识点用为什么应用于这样的关系连起来。比如动态代理节点可以连到Spring AOP再连到Transactional的失效场景再连到分布式事务方案。这样做的好处是面试时被问到任何一个点都能迅速调动周边相关的知识答出来的内容就会显得有广度也有深度。6.2 Java学习路线中Day23所在的位置与后续规划按照我整理的Java学习路线整个周期大致分为基础语法、集合与并发、JVM、常用框架原理、设计模式、分布式与微服务这几个阶段。Day23处在设计模式与框架原理衔接的位置前后分别对应Spring核心机制和分布式基础学习内容已经开始从会用某个语法过渡到思考为什么框架要这么设计。如果你也正在按类似路线自学建议不要跳过设计模式直接背Spring源码很多框架特性就是在使用设计模式的基础上扩展的比如Spring的BeanPostProcessor就很像模板方法模式AOP底层就是动态代理。Day24和Day25的计划我已经定了一个方向是深入Spring IoC与AOP的面试题整理另一个方向是把并发工具类和锁机制再过一遍重点结合前面的数据一致性话题做并发场景题目的综合练习。八股学习不能只输入不输出我的习惯是每学完一个大的板块就找两三个能讲给同事或者朋友听的话题用自己的话把原理讲清楚讲不出来或者被问住的地方就是下一次需要重点补的漏洞。6.3 面试作答时的表达建议与心态调整最后分享几条来自实际面试经验的表达建议。第一回答技术八股时多用是什么、为什么、怎么做的框架不要只背结论。比如问到策略模式先一句话说定义再讲一个真实业务场景再说我是如何用枚举和Map实现注册的最后补充这个方案的局限一套流程走下来面试官对你的评价会比单纯背概念高很多。第二遇到不会的问题可以直接承认同时把这个题目往你熟悉的方向引导。千万不要编答案技术面试里编造一说就露馅有时坦诚地说这个方向我在项目中没直接用过但我理解它的原理可能和某某机制相关反而能展现学习能力和技术敏感度。还有一点是心态问题。Java面试八股文的内容量确实很大尤其是Java基础、集合、并发、JVM、框架源码这些板块看起来让人焦虑。我的经验是把学习目标拆到天每天只安排两到三个主题像Day23这样深度理解四五个核心概念坚持一个月就能覆盖大部分高频考点。重点是每天都要落实到代码和案例中哪怕只是一个小Demo也比只背十遍定义更有用。我在实际准备Java技术八股的过程里最大的体会就是八股只是敲门砖理解才是真本事。Day23作为整个学习计划的缩影无论是面向对象、策略模式、动态代理还是数据一致性本质上都是在训练同一个思维习惯看到一个技术名词首先追问它解决什么问题其次想清楚它怎么实现最后思考它有哪些局限和变种。有了这套习惯面试题怎么换都不容易难倒你日常写代码也会更有章法。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。