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

【iOS】KVC的学习

【iOS】KVC的学习

文章目录

  • 【iOS】KVC的学习
    • 前言
    • KVC
      • 定义
      • KVC设值
      • KVC取值
      • KVC使用keyPath
      • KVC处理异常
        • 处理nil异常
      • KVC的一些应用
        • 修改动态的设置值
        • 实现高阶的消息传递
    • 小结

前言

笔者简单学习了有关与KVC的相关内容,这里写一篇博客简单介绍一下相关内容。

KVC

定义

KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。很多高级的iOS开发技巧都是基于KVC实现的。

KVC的定义是通过对于NSObject的扩展来实现的,下面是几个有关于KVC最重要的四个方法:

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值

这里我们从KVC设置值开始说起:

KVC设值

首先我们要清楚KVC是怎么实现一个设置值的效果的,这里我们举一个例子:[test setValue:@"1223" forKey:@"str"];这条语句在执行的时候,KVC到底执行了那些代码。

  • 程序优先调用set:属性值方法,代码通过setter方法完成设置。注意,这里的是指成员变量名,首字母大小写要符合KVC的命名规则,下同
  • 如果没有找到setName:方法,KVC机制会检查+ (BOOL)accessInstanceVariablesDirectly方法有没有返回YES,默认该方法会返回YES,如果你重写了该方法让其返回NO的话,那么在这一步KVC会执行setValue:forUndefinedKey:方法,不过一般开发者不会这么做。所以KVC机制会搜索该类里面有没有名为**_str** 的成员变量,无论该变量是在类接口处定义,还是在类实现处定义,也无论用了什么样的访问修饰符,只在存在以_命名的变量,KVC都可以对该成员变量赋值。
  • 如果该类即没有set:方法,也没有_成员变量,KVC机制会搜索isStr的成员变量。

所以简而言之就是这个设置值的函数查找成员变量的顺序就是顺序查找名称类似于 _<key>_is<Key><key>is<Key> 的实例变量。只要能找到一个满足条件的成员变量就会给这个成员变量设置我们的一个值,下面给一段代码来讲解一下。

#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface TestObject : NSObject {@publicNSString* isAge;//NSString* _age;
}
@property NSString* str;
@property NSArray* ary;
@endNS_ASSUME_NONNULL_END
#import "TestObject.h"@implementation TestObject
@end#import <Foundation/Foundation.h>
#import "TestObject.h"
int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...TestObject* test = [[TestObject alloc] init];[test setValue:@[] forKey:@"ary"];[test setValue:@"1223" forKey:@"str"];[test setValue:@"12" forKey:@"age"];NSLog(@"%@", test->isAge);//NSLog(@"%@", [test valueForKey:@"_age"]);}return 0;
}

打印结果:

12
Type: Notice | Timestamp: 2024-09-17 16:31:02.784471+08:00 | Process: KVC | Library: KVC | TID: 0xda0dbb

可以看到上面这段代码虽然我们不是一个名字为age的标题,但是还是能打印出一个结果。

然后我们修改一下成员变量部分

@interface TestObject : NSObject {@publicNSString* isAge;NSString* _age;
}

主函数

int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...TestObject* test = [[TestObject alloc] init];[test setValue:@[] forKey:@"ary"];[test setValue:@"1223" forKey:@"str"];[test setValue:@"12" forKey:@"age"];NSLog(@"%@", test->isAge);NSLog(@"%@", test->_age);//NSLog(@"%@", [test valueForKey:@"_age"]);NSLog(@"%@", test.str);NSLog(@"%@", test.ary);}return 0;
}

(null)
Type: Notice | Timestamp: 2024-09-17 17:14:26.416628+08:00 | Process: KVC | Library: KVC | TID: 0xda5d69

12
Type: Notice | Timestamp: 2024-09-17 17:14:26.416670+08:00 | Process: KVC | Library: KVC | TID: 0xda5d69

可以看到我们的isAge这个变量打印出了一个(null)而我们下面的age这个变量则打印出来一个12也就是我们想要的值,这里就说明KVC方法的取值是有一个固定的顺序的。也就是我们上面提到的 _<key>_is<Key><key>is<Key>

同时我们这里如果不想让我们的一个代码实现一个KVC的话,我们可以通过设置+ (BOOL)accessInstanceVariablesDirectly这种方法让他永远返回NO,这样就可以让这个类无法使用KVC。我们先重写下面几个方法,主函数仍旧是上面那一个主函数。

+ (BOOL)accessInstanceVariablesDirectly {return NO;
}
- (id)valueForUndefinedKey:(NSString *)key {NSLog(@"出现异常");return nil;
}
- (void)setValue:(id)value forKey:(NSString *)key {NSLog(@"出现异常,无法设置");
}

打印结果:

出现异常,无法设置。
Type: Notice | Timestamp: 2024-09-17 18:47:05.235218+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

出现异常,无法设置
Type: Notice | Timestamp: 2024-09-17 18:47:05.235285+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

出现异常,无法设置
Type: Notice | Timestamp: 2024-09-17 18:47:05.235285+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

(null)
Type: Notice | Timestamp: 2024-09-17 18:47:05.235326+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

(null)
Type: Notice | Timestamp: 2024-09-17 18:47:05.235326+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

(null)
Type: Notice | Timestamp: 2024-09-17 18:47:05.235326+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

(null)
Type: Notice | Timestamp: 2024-09-17 18:47:05.235340+08:00 | Process: KVC | Library: KVC | TID: 0xdaa7bd

重写这个方法后,如果我们的KVC找不到set< Key >这个方法之后就不会继续向下寻找了。

在这里插入图片描述

正如上图所示,KVC的设值大概就是上图的过程。

KVC取值

有关于KVC取值,一般采用

  • 首先按get< Key >,< key>,is < Key>的顺序方法查找getter方法,找到的话会直接调用。如果是BOOL或者Int等值类型, 会将其包装成一个NSNumber对象。
  • 如果还没有找到,再检查类方法+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默认行为),那么和先前的设值一样,会按_,_is,is的顺序搜索成员变量名,这里不推荐这么做,因为这样直接访问实例变量破坏了封装性,使代码更脆弱。

一般情况按照这三个顺序进行一个查找,笔者这里给出函数。

#import "TestObject.h"@implementation TestObject
-(int)getAge {return 1222;
}
-(int)age {return 120;
}
-(int)isAge {return 10;
}
@end
#import <Foundation/Foundation.h>
#import "TestObject.h"
int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...TestObject* test = [[TestObject alloc] init];[test setValue:@[] forKey:@"ary"];[test setValue:@"1223" forKey:@"str"];[test setValue:@"12" forKey:@"age"];NSLog(@"%@",[test valueForKey:@"age"]);//NSLog(@"%@", test->_age);//NSLog(@"%@", [test valueForKey:@"_age"]);NSLog(@"%@", test.str);//NSLog(@"%@", test.ary);}return 0;
}

打印结果:

1222
Type: Notice | Timestamp: 2024-09-18 22:58:51.536732+08:00 | Process: KVC | Library: KVC | TID: 0xdf2afb

返回的是我们getAge的方法返回的函数。

这时候我们注释getAge,然后重新运行一下

120
Type: Notice | Timestamp: 2024-09-18 23:00:38.285681+08:00 | Process: KVC | Library: KVC | TID: 0xdf33e6

最后我们在注释age,在运行一下得到

10
Type: Notice | Timestamp: 2024-09-18 23:02:06.668767+08:00 | Process: KVC | Library: KVC | TID: 0xdf3d01

最后我们注释isAge,运行一下可以得到。

12
Type: Notice | Timestamp: 2024-09-18 23:05:09.897443+08:00 | Process: KVC | Library: KVC | TID: 0xdf4c04

KVC使用keyPath

有时候我们的要改变的对象可能是比较复杂的,比如说自定义类或者是其他复杂的数据类型,我们如果使用key来一层一层的监控的话,会非常复杂,这时候就出现了keyPath这个方法来简化代码。

如下面的代码,我们先定义一个新的类。

#import <Foundation/Foundation.h>
#import "TestObject.h"
NS_ASSUME_NONNULL_BEGIN@interface NextText : NSObject
@property TestObject* test;
@endNS_ASSUME_NONNULL_END

上面这个自定义类存储了一个属性是我们之前创建的对象。

int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...TestObject* test = [[TestObject alloc] init];NextText* test1 = [[NextText alloc] init];[test1 setValue:test forKey:@"test"];[test1 setValue:@"1222" forKeyPath:@"test.str"];NSLog(@"%@", [test1 valueForKeyPath:@"test.str"]);}return 0;
}

打印结果:

1222
Type: Notice | Timestamp: 2024-09-19 18:24:49.998580+08:00 | Process: KVC | Library: KVC | TID: 0xe07e3c

这里可以看到我们在这里也是成功设置了有关keyPath的内容,然后也通过keyPath来实现了获取对应的数值。所以说我们仅仅需要用一个点语法的形式就可以实现一个修改对应路径的一个值。

KVC处理异常

在一般情况下,我们是不允许KVC来给一个对象赋值为nil的,这时候,我们可能需要自己去处理一下nil异常的部分。比方说,我们传入一个nil给NSInteger的对象的时候,就会出现一个异常的问题,会执行-(void)setNilValueForKey:(NSString *)key这个方法,这个方法会产生一个Crash,所以我们通常需要重写这个方法。

处理nil异常
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface TestObject : NSObject {@publicNSInteger _age;
}
@property NSString* str;
@property NSArray* ary;
@endNS_ASSUME_NONNULL_END
#import "TestObject.h"@implementation TestObject
- (void)setNilValueForKey:(NSString *)key {if ([key isEqualToString:@"age"]) {NSLog(@"不能设置成nil状态%@", key);_age = 11;} else {[super setNilValueForKey:key];}
}
@end
#import <Foundation/Foundation.h>
#import "TestObject.h"
#import "NextText.h"
int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...TestObject* test = [[TestObject alloc] init];[test setValue:nil forKey:@"age"];NSLog(@"%@", [test valueForKey:@"age"]);//NSLog(@"%@", test.ary);}return 0;
}

然后执行代码的打印结果是:

不能设置成nil状态age
Type: Notice | Timestamp: 2024-09-19 19:31:52.434134+08:00 | Process: KVC | Library: KVC | TID: 0xe16087

11
Type: Notice | Timestamp: 2024-09-19 19:31:52.434305+08:00 | Process: KVC | Library: KVC | TID: 0xe16087

Program ended with exit code: 0
Type: stdio

KVC的一些应用

修改动态的设置值

这是KVC最简单的应用。

实现高阶的消息传递

首先,我们要明白对于容器使用一个KVC,并没有对于我们的容器进行一个操作,实际上是将这个方法传递给容器中的每一个元素,然后再重新返回一个容器,所以这里我们实现一些特殊的效果,通过操作一个容器来返回一个符合我们需求的容器。

int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...NSArray* arrStr = @[@"english",@"franch",@"chinese"];NSArray* arrCapStr = [arrStr valueForKey:@"capitalizedString"];for (NSString* str  in arrCapStr) {NSLog(@"%@",str);}NSArray* arrCapStrLength = [arrStr valueForKeyPath:@"capitalizedString.length"];for (NSNumber* length  in arrCapStrLength) {NSLog(@"%ld",(long)length.integerValue);}//NSLog(@"%@", test.ary);}return 0;
}

打印结果:

English
Type: Notice | Timestamp: 2024-09-19 19:52:26.638075+08:00 | Process: KVC | Library: KVC | TID: 0xe198e4
Franch
Type: Notice | Timestamp: 2024-09-19 19:52:26.638130+08:00 | Process: KVC | Library: KVC | TID: 0xe198e4
Chinese
Type: Notice | Timestamp: 2024-09-19 19:52:26.638150+08:00 | Process: KVC | Library: KVC | TID: 0xe198e4
7
Type: Notice | Timestamp: 2024-09-19 19:52:26.638865+08:00 | Process: KVC | Library: KVC | TID: 0xe198e4
6
Type: Notice | Timestamp: 2024-09-19 19:52:26.638895+08:00 | Process: KVC | Library: KVC | TID: 0xe198e4
7
Type: Notice | Timestamp: 2024-09-19 19:52:26.638912+08:00 | Process: KVC | Library: KVC | TID: 0xe198e4
Program ended with exit code: 0
Type: stdio

可以看到这里我们通过KVC来实现了一个让容器中所有字符串第一个字符大写的容器。

小结

笔者在这里简单介绍了一下有关于KVC的使用,之后还会继续学习相关的内容。

相关文章:

【iOS】KVC的学习

【iOS】KVC的学习 文章目录 【iOS】KVC的学习前言KVC定义KVC设值KVC取值KVC使用keyPathKVC处理异常处理nil异常 KVC的一些应用修改动态的设置值实现高阶的消息传递 小结 前言 笔者简单学习了有关与KVC的相关内容&#xff0c;这里写一篇博客简单介绍一下相关内容。 KVC 定义 KV…...

影刀RPA实战:网页爬虫之药品数据

1 实战目标 这次给大家带来的实战示例是采集中国医药信息平台上的药品数据&#xff0c;主要获取药品名称&#xff0c;介绍&#xff0c;药品类型&#xff0c;处方类型&#xff0c;医保类型&#xff0c;参考价格&#xff0c;药品成分&#xff0c;性状&#xff0c;适应病症&#…...

python禁止位置传参函数

这种函数定义方式使用了 Python 3.x 中的关键字参数&#xff08;keyword-only arguments&#xff09;的特性&#xff0c;通过在参数列表中使用 * 符号作为分隔符&#xff0c;来明确指示该函数之后的参数必须使用关键字&#xff08;即参数名&#xff09;来传递&#xff0c;而不能…...

java面试题第一弹

Java 的基本数据类型有哪些&#xff1f; Java 的基本数据类型&#xff08;primitive data types&#xff09;包括以下八种&#xff1a; byte&#xff1a; 尺寸&#xff1a;1 字节&#xff08;8 位&#xff09;。范围&#xff1a;-128 到 127。用途&#xff1a;节省内存&#x…...

住宅HTTP代理:提升网络隐私与安全的新选择

在互联网时代&#xff0c;我们的在线隐私和安全变得越来越重要。无论是浏览网页、进行在线交易&#xff0c;还是访问受限内容&#xff0c;住宅HTTP代理都能为我们提供一种可靠的解决方案。今天&#xff0c;我们就来深入探讨一下住宅HTTP代理&#xff0c;看看它是如何帮助我们提…...

字符串函数(2)

目录 前言1. strlen1.1 strlen函数的理解和使用1.2 strlen函数的模拟实现 2. strcpy2.1 strcpy函数的理解和使用2.2 strcpy函数的模拟实现 3.strcat3.1 strcat函数的理解和使用3.2 strcat 函数的模拟实现 前言 在上一篇文章中&#xff0c;我们对字符分类函数和字符转换函数进行…...

Linux--守护进程与会话

进程组 概念 进程组就是一个或多个进程的集合。 一个进程组可以包含多个进程。 下面我们通过一句简单的命令行来展示&#xff1a; 为什么会有进程组&#xff1f; 批量操作&#xff1a;进程组允许将多个进程组织在一起&#xff0c;形成一个逻辑上的整体。当需要对多个进程…...

C++ 笔试常用算法模板

C 笔试常用算法模板 一、二叉树遍历DFSBFS 二、回溯模板三、动态规划01背包朴素版本滚动数组优化 完全背包朴素版本滚动数组优化 最长递增子序列朴素版本贪心二分优化 最长公共子序列最长回文子串 四、图建图邻接矩阵邻接表 图的遍历DFSBFS 拓扑排序并查集最小生成树Kruskalpri…...

李宏毅2023机器学习作业HW07解析和代码分享

ML2023Spring - HW7 相关信息&#xff1a; 课程主页 课程视频 Kaggle link 回来了 : ) Sample code HW07 视频 HW07 PDF 个人完整代码分享: GitHub | Gitee | GitCode P.S. HW7 的代码都很易懂&#xff0c;可以和 2024 年的新课&#xff1a;生成式AI导论做一个很好的衔接&#…...

ansible远程自动化运维、常用模块详解

一、ansible是基于python开发的配置管理和应用部署工具&#xff1b;也是自动化运维的重要工具&#xff1b;可以批量配置、部署、管理上千台主机&#xff1b;只需要在一台主机配置ansible就可以完成其它主机的操作。 1.操作模式&#xff1a; 模块化操作&#xff0c;命令行执行…...

【若依框架】按时间查询数据的操作

【若依框架】按时间查询数据的操作 若依框架按起止时间查询数据示例&#xff1a; Date tempDate DateUtil.offsetDay(new Date(), -days);Map<String, Object> map new HashMap<>();map.put("beginRecordTime", DateUtil.beginOfHour(tempDate));map.…...

人工智能将来好就业吗?

人工智能将来好就业吗? 随着科技的不断进步&#xff0c;人工智能&#xff08;AI&#xff09;正逐渐成为推动全球经济发展的核心力量之一。从智能机器人到自动驾驶汽车&#xff0c;从语音识别到图像分析&#xff0c;AI正在改变我们的工作方式以及我们与世界的互动方式。那么&am…...

JAVA SE 11

文章目录 JDK 11 特性介绍语法增强1. String类的增强2. Optional类的增强3. 新的HTTP/2客户端4. var关键字的扩展5. Collection接口的增强 语法改进JDK 11引入的一些语法改进 详细介绍1. 模块化系统&#xff08;Java平台模块系统&#xff0c;JPMS&#xff09;2. HTTP客户端3. 改…...

【MySQ】在MySQL里with 的用法

在MySQL中&#xff0c;WITH语句通常与公用表表达式&#xff08;Common Table Expressions&#xff0c;简称CTE&#xff09;一起使用。CTE是一种临时的结果集&#xff0c;类似于视图或子查询&#xff0c;它们在查询中被定义并且可以在一个或多个SELECT、INSERT、UPDATE或DELETE语…...

多源最短路径

文章目录 1. 01 矩阵&#xff08;542&#xff09;2. 飞地的数量&#xff08;1020&#xff09;3. 地图分析&#xff08;1162&#xff09;4. 地图中的最高点&#xff08;1765&#xff09; 1. 01 矩阵&#xff08;542&#xff09; 题目描述&#xff1a; 算法原理&#xff1a; 这…...

在 Mac 中设置环境变量

目录 什么是环境变量&#xff0c;为什么它们重要&#xff1f;什么是环境变量&#xff1f;举个例子 如何查看环境变量如何设置和修改环境变量1. 临时设置环境变量2. 永久设置环境变量3. 修改现有环境变量 环境变量在开发中的应用在 Node.js 项目中使用环境变量在 Python 项目中使…...

记录一次ubuntu /mysql/redis/nginx等 系统安装

没想到还会做一次系统安装配置类的工作&#xff0c;没办法&#xff0c;碰到问题了&#xff0c;总得解决。 安装 &网络配置 从网上下载了ubuntu 18.04.6的安装包&#xff0c;用UltraISO做安装盘&#xff0c;到服务器上修改了下启动顺序&#xff0c;ubuntu的安装非常简单&a…...

大型语言模型 (LLM) 劫持攻击不断升级,导致每天损失超过 100,000 美元

Sysdig 威胁研究团队 (TRT) 报告称&#xff0c;LLMjacking&#xff08;大型语言模型劫持&#xff09;事件急剧增加&#xff0c;攻击者通过窃取的云凭证非法访问大型语言模型 (LLM)。 这一趋势反映了 LLM 访问黑市的不断增长&#xff0c;攻击者的动机包括个人使用和规避禁令和制…...

Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾收集器

文章目录 垃圾回收机制Stop-the-World垃圾收集器垃圾收集器分类Serial 收集器Serial Old 收集器ParNew 收集器Parallel Scavenge 收集器Parallel Old 收集器CMS 收集器CMS 收集器缺点 G1 收集器G1 收集器特点G1 收集器的分代理念G1 收集器运作过程 垃圾回收机制 垃圾回收&…...

nano 命令:文本编辑器

一、命令简介 ​nano​ 是一个简单易用的文本编辑器&#xff0c;适合初学者和那些不需要复杂功能的用户。 ​​ ‍ 相关命令&#xff08;不同难度的编辑器&#xff09;&#xff1a; 初级难度&#xff1a;nano中级难度&#xff1a;vim终极难度&#xff1a;Emacs ‍ 二、命…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

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

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

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

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

Java并发编程实战 Day 11:并发设计模式

【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天&#xff0c;今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案&#xff0c;它们不仅提供了优雅的设计思路&#xff0c;还能显著提升系统的性能…...

从实验室到产业:IndexTTS 在六大核心场景的落地实践

一、内容创作&#xff1a;重构数字内容生产范式 在短视频创作领域&#xff0c;IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色&#xff0c;生成的 “各位吴彦祖们大家好” 语音相似度达 97%&#xff0c;单条视频播放量突破百万…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...