当前位置: 首页 > news >正文

《程序猿之设计模式实战 · 适配器模式》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗

🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍

文章目录

      • 写在前面的话
      • 基础介绍
      • 代码实现
      • Spring 中的适配器模式
      • 适配器VS装饰者
      • 适配器实操补充
      • 总结陈词

写在前面的话

本篇文章继续介绍一下适配器模式,单词为Adapter。日常生活中适配器的场景也随处可见,例如USB、插座等转换头,或电压转换处理,总之,起中转适配作用的,都可以考虑用适配器模式。

工作中的场景就更不用说了,新老服务之间中转的桥梁、服务、工具,都可以称之为Adapter,那这个适配器模式到底是什么样的,且听我娓娓道来。

相关文章:
《程序猿之设计模式实战 · 策略模式》
《程序猿之设计模式实战 · 装饰者模式》
《程序猿之设计模式实战 · 池化思想》
《程序猿之设计模式实战 · 观察者模式》
《程序猿之设计模式实战 · 责任链模式》
《程序猿之设计模式实战 · 模板方法》


基础介绍

基础概念:

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个接口转换成客户端所期望的另一个接口。

适配器模式使得原本由于接口不兼容而无法一起工作的类可以一起工作。

主要组成:

适配器模式通常由以下几个角色组成:

  1. 目标接口(Target):客户端所期望的接口。
  2. 源类(Adaptee):需要被适配的类,通常是一个已有的类。
  3. 适配器(Adapter):实现目标接口,并持有源类的实例,负责将源类的接口转换为目标接口。

使用场景:

  • 当你希望使用一些现有的类,但它们的接口与您所需要的接口不兼容时。
  • 当你希望创建一个可重用的类,它可以与一些不相关的类(即接口不兼容的类)一起工作时。
  • 当你希望通过多个类的组合来实现某个功能,而这些类的接口不一致时。

总结一下:

适配器模式通过将不兼容的接口进行适配,使得不同的类可以协同工作。在 Spring 框架中,适配器模式的应用使得不同类型的处理器和视图能够以统一的方式进行处理,从而提高了系统的灵活性和可扩展性。


代码实现

挺简单的一段示例,也是对原有类的增强,使之可以间接成为目标接口。

// 目标接口
interface Target {void request();
}// 源类
class Adaptee {public void specificRequest() {System.out.println("Called specificRequest()");}
}// 适配器
class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {// 调用源类的方法adaptee.specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request(); // 输出: Called specificRequest()}
}

Spring 中的适配器模式

在 Spring 框架中,适配器模式被广泛应用于多个地方,尤其是在 MVC 模块中。以下是一些主要的应用场景:

1、HandlerMapping:Spring MVC 中的 HandlerMapping 使用适配器模式来将请求映射到处理器(Controller)。不同类型的处理器(如注解驱动的控制器、传统的控制器等)可以通过适配器进行统一处理。

2、HandlerAdapter:Spring MVC 中的 HandlerAdapter 是适配器的具体实现,它允许不同类型的处理器(如 SimpleControllerHandlerAdapter、AnnotationMethodHandlerAdapter 等)以统一的方式处理请求。

3、ViewResolver:在视图解析过程中,Spring 使用适配器模式来支持不同类型的视图(如 JSP、Thymeleaf 等)。

以HandlerMapping为例,是如何利用到适配器模式?

在 Spring 框架中,HandlerMapping 是一个重要的组件,它负责将 HTTP 请求映射到相应的处理器(Handler)。为了实现这一点,Spring 使用了适配器模式来处理不同类型的请求处理器(如控制器)。

适配器模式在 HandlerMapping 中的应用,步骤如下:

1、接口与实现

在 Spring 中,HandlerMapping 会将请求映射到一个处理器(Handler),而这个处理器可能是不同类型的对象,比如:

  • 控制器类(例如,使用 @Controller 注解的类)
  • 函数式处理器(例如,使用 @RequestMapping 注解的方法)

为了能够处理这些不同类型的处理器,Spring 使用了适配器模式。

2、适配器接口

Spring 定义了一个适配器接口,例如 HandlerAdapter,它为不同类型的处理器提供了统一的调用方式。这个接口定义了一个方法,比如 handle(),用于处理请求。

public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

3、具体适配器

Spring 提供了多个具体的适配器实现,例如:

RequestMappingHandlerAdapter:用于处理使用 @RequestMapping 注解的控制器方法。

SimpleControllerHandlerAdapter:用于处理实现了 Controller 接口的传统控制器。

每个适配器实现了 HandlerAdapter 接口,并提供了对特定类型处理器的支持。

public class RequestMappingHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return (handler instanceof RequestMappingHandler);}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 处理请求}
}

4、HandlerMapping 的工作流程

请求到达:当一个 HTTP 请求到达时,HandlerMapping 会根据请求的 URL 找到对应的处理器。

适配器选择:HandlerMapping 会遍历所有注册的 HandlerAdapter,找到一个支持找到的处理器的适配器。

请求处理:一旦找到合适的适配器,HandlerMapping 会调用适配器的 handle() 方法,传递请求和响应对象,以及处理器。

返回结果:适配器处理请求并返回结果(如 ModelAndView),最终将响应返回给客户端。

总结一下,通过适配器模式,Spring 能够灵活地支持多种类型的请求处理器,而不需要在 HandlerMapping 中硬编码每种处理器的处理逻辑。这种设计使得框架具有良好的扩展性和可维护性,允许开发者轻松添加新的处理器类型和适配器。


适配器VS装饰者

观察了示例代码,可以发现,和装饰者模式有点像,都是扩展增强了原有对象,那两者有什么区别呢?

适配器模式和装饰者模式虽然在结构上有相似之处,但它们的目的和使用场景是不同的,下面是它们的主要区别:

1、先看适配器模式

1)目的:接口转换,适配器模式的主要目的是将一个类的接口转换为客户端所期望的另一个接口。它使得原本由于接口不兼容而无法一起工作的类可以一起工作。

2)使用场景:当你希望使用一些现有的类,但它们的接口与您所需要的接口不兼容时。例如,将一个旧的 API 适配到新的接口,以便可以在新的系统中使用。

3)结构:适配器通常包含一个源类的实例,并实现目标接口。适配器负责将目标接口的方法调用转发到源类的方法。

2、再看装饰者模式

1、目的:功能扩展,装饰者模式的主要目的是在不改变对象自身的情况下,动态地为对象添加额外的功能。它允许在运行时对对象进行扩展。

2、使用场景:当你希望在不修改现有类的情况下,给对象添加新的行为或功能时。例如,为一个图形对象添加边框、阴影等装饰效果。

3、结构装饰者通常包含一个被装饰对象的实例,并实现与被装饰对象相同的接口。装饰者可以在调用被装饰对象的方法之前或之后添加额外的行为。

3、总结一下

适配器模式:关注于接口的转换,使得不兼容的接口可以协同工作。

装饰者模式:关注于功能的扩展,通过组合的方式为对象添加新的行为。

【代理、桥接、装饰器、适配器的区别】

  • 代理模式:代理模式在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这是它跟装饰器模式最大的不同。
  • 桥接模式:桥接模式的目的是将接口部分和实现部分分离,而让它们可以较为容易、独立地加以改变。
  • 装饰器模式:装饰器模式在不改变原始类接口的情况下,对原始类功能进行增强,并且支持多个装饰器的嵌套使用。
  • 适配器模式:适配器模式是一种时候的补救策略,适配器提供跟原始类不同的接口,而代理模式、装饰器模式提供的都是跟原来类相同的接口。

适配器实操补充

经典案例一


// 类适配器: 基于继承
// 自己扩展的,客户端期望得到的接口,里面还可以包含被适配者没有的接口
public interface ITarget {void f1();void f2();void fc();
}//被适配者(外部系统)
//理解为外国的电源插座,这些方法不会暴露给客户端直接调用,因此不支持或者说不好用
public class Adaptee {public void fa() { //... }public void fb() { //... }public void fc() { //... }
}//适配器类,用于替换被适配者完成功能
//理解为转接头,负责两个事情,提供方法给客户端调用,方法内部会调用目标(国外电源插座)的方法
public class Adaptor extends Adaptee implements ITarget {public void f1() {super.fa();}public void f2() {//...重新实现f2()...}// 这里fc()不需要实现,直接继承自Adaptee,这是跟对象适配器最大的不同点
}// 对象适配器:基于组合
public interface ITarget {void f1();void f2();void fc();
}public class Adaptee {public void fa() { //... }public void fb() { //... }public void fc() { //... }
}public class Adaptor implements ITarget {private Adaptee adaptee;public Adaptor(Adaptee adaptee) {this.adaptee = adaptee;}public void f1() {adaptee.fa(); //委托给Adaptee}public void f2() {//...重新实现f2()...}public void fc() {adaptee.fc();}
}

经典案例二(类适配器模式)

在上图中可以看出,Adaptee类(被适配者、外国插座)并没有sampleOperation2()方法,而客户端则期待这个方法。为使客户端能够使用 Adaptee 类,提供一个中间环节,即类 Adapter(适配器、转换头),把 Adaptee 的 API与 Target 类的API衔接起来。Adapter 与 Adaptee 是继承关系,这决定了这个适配器模式是类的:

模式所涉及的角色有:

1、目标(Target)角色:这就是所期待得到的接口。

2、源(Adapee)角色:现在需要适配的接口。

3、适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。

public interface Target {/*** 这是源类Adaptee也有的方法*/public void sampleOperation1(); /*** 这是源类Adapteee没有的方法*/public void sampleOperation2(); 
}//上面给出的是目标角色的源代码,这个角色是以一个JAVA接口的形式实现的。
//可以看出,这个接口声明了两个方法:sampleOperation1()和sampleOperation2()。
//而源角色Adaptee是一个具体类,它有一个sampleOperation1()方法,但是没有sampleOperation2()方法。
public class Adaptee {public void sampleOperation1(){}
}//适配器角色Adapter扩展了Adaptee,同时又实现了目标(Target)接口。由于Adaptee没有提供sampleOperation2()方法,而目标接口又要求这个方法
//因此适配器角色Adapter实现了这个方法。
public class Adapter extends Adaptee implements Target {/*** 由于源类Adaptee没有方法sampleOperation2()* 因此适配器补充上这个方法*/@Overridepublic void sampleOperation2() {//写相关的代码}}

经典案例三(对象适配器模式)

与类的适配器模式一样,对象的适配器模式把被适配的类的API转换成为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。

PS:其实基本一样,就是继承改为组合。

从上图可以看出,Adaptee类并没有sampleOperation2()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。

public interface Target {/*** 这是源类Adaptee也有的方法*/public void sampleOperation1(); /*** 这是源类Adapteee没有的方法*/public void sampleOperation2(); 
}public class Adaptee {public void sampleOperation1(){}   
}public class Adapter {private Adaptee adaptee;public Adapter(Adaptee adaptee){this.adaptee = adaptee;}/*** 源类Adaptee有方法sampleOperation1* 因此适配器类直接委派即可*/public void sampleOperation1(){this.adaptee.sampleOperation1();}/*** 源类Adaptee没有方法sampleOperation2* 因此由适配器类需要补充此方法*/public void sampleOperation2(){//写相关的代码}
}

总结陈词

怎么说呢,适配器模式还是很强大的,它为我们带来:

1、更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。

2、更好的扩展性:在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。

但它也有一些缺点:过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

最终是否采用,还是根据实际情况决定,纸上得来终觉浅,绝知此事要躬行

💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

相关文章:

《程序猿之设计模式实战 · 适配器模式》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...

Elasticsearch案例

目录 一、创建索引 二、准备数据 三、环境搭建 (1)环境搭建 (2)创建实体类 (3)实现Repository接口 四、实现自动补全功能 五、实现高亮搜索关键字功能 (1)在repository接口中…...

SpringBoot 项目如何使用 pageHelper 做分页处理 (含两种依赖方式)

分页是常见大型项目都需要的一个功能,PageHelper是一个非常流行的MyBatis分页插件,它支持多数据库分页,无需修改SQL语句即可实现分页功能。 本文在最后展示了两种依赖验证的结果。 文章目录 一、第一种依赖方式二、第二种依赖方式三、创建数…...

GSR关键词排名系统是针对谷歌seo的吗?

是的,GSR关键词排名系统专门针对谷歌SEO,具体通过外部优化手段快速提升关键词排名。不同于传统的SEO策略,GSR系统并不依赖于对网站内容的调整或内部优化,完全通过站外操作实现效果。这意味着,用户不需要花费精力在网站…...

HarmonyOS Next开发----使用XComponent自定义绘制

XComponent组件作为一种绘制组件,通常用于满足用户复杂的自定义绘制需求,其主要有两种类型"surface和component。对于surface类型可以将相关数据传入XComponent单独拥有的NativeWindow来渲染画面。 由于上层UI是采用arkTS开发,那么想要…...

什么是电商云手机?可以用来干什么?

随着电商行业的迅速发展,云手机作为一种创新工具正逐渐进入出海电商领域。专为外贸市场量身定制的出海电商云手机,已经成为许多外贸企业和出海电商卖家的必备。本文将详细介绍电商云手机是什么以及可以用来做什么。 与国内云手机偏向于游戏场景不同&…...

Python 2 和 Python 3的差异

Python 2 和 Python 3 之间有许多差异,Python 3 是 Python 语言的更新版本,目的是解决 Python 2 中的一些设计缺陷,并引入更现代的编程方式。以下是 Python 2 和 Python 3 之间的一些主要区别: 文章目录 1. print 语句2. 整除行为…...

Leetcode 第 139 场双周赛题解

Leetcode 第 139 场双周赛题解 Leetcode 第 139 场双周赛题解题目1:3285. 找到稳定山的下标思路代码复杂度分析 题目2:3286. 穿越网格图的安全路径思路代码复杂度分析 题目3:3287. 求出数组中最大序列值思路代码复杂度分析 题目4:…...

spring 注解 - @NotEmpty - 确保被注解的字段不为空,而且也不是空白(即不是空字符串、不是只包含空格的字符串)

NotEmpty 是 Bean Validation API 提供的注解之一,用于确保被注解的字段不为空。它检查字符串不仅不是 null,而且也不是空白(即不是空字符串、不是只包含空格的字符串)。 这个注解通常用在 Java 应用程序中,特别是在处…...

深入理解华为仓颉语言的数值类型

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在编程过程中,数据处理是开发者必须掌握的基本技能之一。无论是开发应用程序还是进行算法设计,了解不同数据类型的特性和用途都至关重要。本文将深入探讨华为仓颉语言中的基本数…...

WPF 的TreeView的TreeViewItem下动态生成TreeViewItem

树形结构仅部分需要动态生成TreeViewItem的可以参考本文。 xaml页面 <TreeView MinWidth"220" ><TreeViewItem Header"功能列表" ItemsSource"{Binding Functions}"><TreeViewItem.ItemTemplate><HierarchicalDataTempla…...

使用Go语言的互斥锁(Mutex)解决并发问题

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在并发编程中,由于存在竞争条件和数据竞争,我们需要将某些代码片段设定为临界区,并使用互斥锁(Mutex)等同步原语来保护这些临界区。本文将详细介绍Go语言标准库中Mutex的使用方法,以及如何利用它来解决实际…...

Android平台Unity3D下如何同时播放多路RTMP|RTSP流?

技术背景 好多开发者&#xff0c;提到希望在Unity的Android头显终端&#xff0c;播放2路以上RTMP或RTSP流&#xff0c;在设备性能一般的情况下&#xff0c;对Unity下的RTMP|RTSP播放器提出了更高的要求。实际上&#xff0c;我们在前几年发布Unity下直播播放模块的时候&#xf…...

网络:TCP协议-报头字段

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 文章目录 前言一、TCP协议格式16位源端口号 和 16位目的端口号4位首部长度16位窗口大小32位序号 和 32位确认序号6种标记位 和 16位紧急指针 总结 前言 本文是我对于TCP协…...

JAVA基础:HashMap底层数组容量控制,TreeMap底层存取机制,位运算符,原码反码补码

List常用实现类 List集合常用的实现类有3个 &#xff0c; ArrayList , LinkedList , Vector ArrayList 类似于我们之前的ArrayBox 底层使用数组存储元素&#xff0c; 插入删除的效率低&#xff0c;检索的效率高 当底层数组存储容量不足时&#xff0c;会进行扩容&#xff0c;…...

【Redis】Redis 缓存设计:抗住百万并发量的最佳实践

目录 1. Redis 缓存设计原则1.1 高可用性1.2 数据一致性1.3 读写分离 2. 缓存策略2.1 常用缓存策略2.1.1 缓存穿透2.1.2 缓存雪崩2.1.3 缓存击穿 2.2 额外缓存策略2.2.1 更新策略2.2.2 预热策略2.2.3 侧写缓存 3. Redis 架构设计3.1 单机 vs 集群3.2 Redis 集群示例架构 4. 性能…...

【hot100-java】【缺失的第一个正数】

R9-普通数组篇 class Solution {public int firstMissingPositive(int[] nums) {int nnums.length;for (int i0;i<n;i){while(nums[i]>0&&nums[i]<n&&nums[nums[i]-1]!nums[i]){//交换nums[i]和nums[nums[i]-1]int temp nums[nums[i]-1];nums[nums[i]…...

独立站新手教程转化篇:如何做好移动端优化?

随着移动设备在全球范围内的普及&#xff0c;越来越多消费者选择通过手机或平板电脑&#xff0c;来进行线上购物。因此移动端优化&#xff0c;因此移动端优化&#xff0c;也成为独立站卖家必须重视的一个关键环节。那么独立站移动端需要做好哪些优化工作呢&#xff1f; 选择响…...

Mybatis Plus分页查询返回total为0问题

Mybatis Plus分页查询返回total为0问题 一日&#xff0c;乌云密布&#xff0c;本人看着mybatis plus的官方文档&#xff0c;随手写了个分页查询&#xff0c;如下 Page<Question> questionPage questionService.page(new Page<>(current, size),questionService.g…...

VulnHub-Narak靶机笔记

Narak靶机笔记 概述 Narak是一台Vulnhub的靶机&#xff0c;其中有简单的tftp和webdav的利用&#xff0c;以及motd文件的一些知识 靶机地址&#xff1a; https://pan.baidu.com/s/1PbPrGJQHxsvGYrAN1k1New?pwda7kv 提取码: a7kv 当然你也可以去Vulnhub官网下载 一、nmap扫…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

《Offer来了:Java面试核心知识点精讲》大纲

文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...