HarmonyOS:@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

装饰器仅能观察到第一层的变化,但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。这就引出了@Observed/@ObjectLink装饰器。

说明
从API version 9开始,这两个装饰器支持在ArkTS卡片中使用。
从API version 11开始,这两个装饰器支持在元服务中使用。

一、概述

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

  • 被@Observed装饰的类,可以被观察到属性的变化;
  • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
  • @Observed用于嵌套类场景中,观察对象类属性变化,要配合自定义组件使用(示例详见嵌套对象),如果要做数据双/单向同步,需要搭配@ObjectLink或者@Prop使用(示例详见@Prop与@ObjectLink的差异)。

二、限制条件

  • 使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。
  • @ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。

三、装饰器说明

@Observed类装饰器说明
装饰器参数
类装饰器装饰class。需要放在class的定义前,使用new创建类对象。
@ObjectLink变量装饰器说明
装饰器参数
允许装饰的变量类型必须为被@Observed装饰的class实例,必须指定类型。
不支持简单类型,可以使用@Prop。
支持继承Date、Array的class实例,API11及以上支持继承Map、Set的class实例。示例见观察变化。
API11及以上支持@Observed装饰类和undefined或null组成的联合类型,比如ClassA | ClassB, ClassA | undefined 或者 ClassA | null, 示例见@ObjectLink支持联合类型。@ObjectLink的属性是可以改变的,但是变量的分配是不允许的,也就是说这个装饰器装饰变量是只读的,不能被改变。
被装饰变量的初始值不允许。

@ObjectLink装饰的数据为可读示例。

// 允许@ObjectLink装饰的数据属性赋值
this.objLink.a= ...
// 不允许@ObjectLink装饰的数据自身赋值
this.objLink= ...

说明
@ObjectLink装饰的变量不能被赋值,如果要使用赋值操作,请使用@Prop。

  • @Prop装饰的变量和数据源的关系是是单向同步,@Prop装饰的变量在本地拷贝了数据源,所以它允许本地更改,如果父组件中的数据源有更新,@Prop装饰的变量本地的修改将被覆盖;
  • @ObjectLink装饰的变量和数据源的关系是双向同步,@ObjectLink装饰的变量相当于指向数据源的指针。禁止对@ObjectLink装饰的变量赋值,如果一旦发生@ObjectLink装饰的变量的赋值,则同步链将被打断。因为@ObjectLink装饰的变量通过数据源(Object)引用来初始化。对于实现双向数据同步的@ObjectLink,赋值相当于更新父组件中的数组项或者class的属性,TypeScript/JavaScript不能实现,会发生运行时报错。

四、变量的传递/访问规则说明

@ObjectLink传递/访问说明
从父组件初始化必须指定。
初始化@ObjectLink装饰的变量必须同时满足以下场景:
- 类型必须是@Observed装饰的class。
- 初始化的数值需要是数组项,或者class的属性。
- 同步源的class或者数组必须是@State,@Link,@Provide,@Consume或者@ObjectLink装饰的数据。
同步源是数组项的示例请参考对象数组。初始化的class的示例请参考嵌套对象。
与源对象同步双向。
可以初始化子组件允许,可用于初始化常规变量、@State、@Link、@Prop、@Provide

初始化规则图示
在这里插入图片描述

五、观察变化和行为表现

5.1 观察变化

@Observed装饰的类,如果其属性为非简单类型,比如class、Object或者数组,也需要被@Observed装饰,否则将观察不到其属性的变化。

class Child {public num: number;constructor(num: number) {this.num = num;}
}@Observed
class Parent {public child: Child;public count: number;constructor(child: Child, count: number) {this.child = child;this.count = count;}
}

以上示例中,Parent被@Observed装饰,其成员变量的赋值的变化是可以被观察到的,但对于Child,没有被@Observed装饰,其属性的修改不能被观察到。

@ObjectLink parent: Parent// 赋值变化可以被观察到
this.parent.child = new Child(5)
this.parent.count = 5// Child没有被@Observed装饰,其属性的变化观察不到
this.parent.child.num = 5

@ObjectLink:@ObjectLink只能接收被@Observed装饰class的实例,推荐设计单独的自定义组件来渲染每一个数组或对象。此时,对象数组或嵌套对象(属性是对象的对象称为嵌套对象)需要两个自定义组件,一个自定义组件呈现外部数组/对象,另一个自定义组件呈现嵌套在数组/对象内的类对象。可以观察到:

  • 其属性的数值的变化,其中属性是指Object.keys(observedObject)返回的所有属性,示例请参考嵌套对象
  • 如果数据源是数组,则可以观察到数组item的替换,如果数据源是class,可观察到class的属性的变化,示例请参考对象数组

继承Date的class时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。

@Observed
class DateClass extends Date {constructor(args: number | string) {super(args)}
}@Observed
class NewDate {public data: DateClass;constructor(data: DateClass) {this.data = data;}
}@Component
struct Child {label: string = 'date';@ObjectLink data: DateClass;build() {Column() {Button(`child increase the day by 1`).onClick(() => {this.data.setDate(this.data.getDate() + 1);})DatePicker({start: new Date('1970-1-1'),end: new Date('2100-1-1'),selected: this.data})}}
}@Entry
@Component
struct Parent {@State newData: NewDate = new NewDate(new DateClass('2023-1-1'));build() {Column() {Child({ label: 'date', data: this.newData.data })Button(`parent update the new date`).onClick(() => {this.newData.data = new DateClass('2023-07-07');})Button(`ViewB: this.newData = new NewDate(new DateClass('2023-08-20'))`).onClick(() => {this.newData = new NewDate(new DateClass('2023-08-20'));})}}
}

继承Map的class时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。详见继承Map类

继承Set的class时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。详见继承Set类

六、框架行为

6.1 初始渲染:
  1. @Observed装饰的class的实例会被不透明的代理对象包装,代理了class上的属性的setter和getter方法
  2. 子组件中@ObjectLink装饰的从父组件初始化,接收被@Observed装饰的class的实例,@ObjectLink的包装类会将自己注册给@Observed class。
6.2 属性更新:

当@Observed装饰的class属性改变时,会执行到代理的setter和getter,然后遍历依赖它的@ObjectLink包装类,通知数据更新。

七、使用场景

7.1 嵌套对象

说明
NextID是用来在ForEach循环渲染过程中,为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。

// objectLinkNestedObjects.ets
let NextID: number = 1;@Observed
class Bag {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}@Observed
class User {public bag: Bag;constructor(bag: Bag) {this.bag = bag;}
}@Observed
class Book {public bookName: BookName;constructor(bookName: BookName) {this.bookName = bookName;}
}@Observed
class BookName extends Bag {public nameSize: number;constructor(nameSize: number) {// 调用父类方法对nameSize进行处理super(nameSize);this.nameSize = nameSize;}
}@Component
struct ViewA {label: string = 'ViewA';@ObjectLink bag: Bag;build() {Column() {Text(`ViewA [${this.label}] this.bag.size = ${this.bag.size}`).fontColor('#ffffffff').backgroundColor('#ff3d9dba').width(320).height(50).borderRadius(25).margin(10).textAlign(TextAlign.Center)Button(`ViewA: this.bag.size add 1`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.bag.size += 1;})}}
}@Component
struct ViewC {label: string = 'ViewC1';@ObjectLink bookName: BookName;build() {Row() {Column() {Text(`ViewC [${this.label}] this.bookName.size = ${this.bookName.size}`).fontColor('#ffffffff').backgroundColor('#ff3d9dba').width(320).height(50).borderRadius(25).margin(10).textAlign(TextAlign.Center)Button(`ViewC: this.bookName.size add 1`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.bookName.size += 1;console.log('this.bookName.size:' + this.bookName.size)})}.width(320)}}
}@Entry
@Component
struct ViewB {@State user: User = new User(new Bag(0));@State child: Book = new Book(new BookName(0));build() {Column() {ViewA({ label: 'ViewA #1', bag: this.user.bag }).width(320)ViewC({ label: 'ViewC #3', bookName: this.child.bookName }).width(320)Button(`ViewB: this.child.bookName.size add 10`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.child.bookName.size += 10console.log('this.child.bookName.size:' + this.child.bookName.size)})Button(`ViewB: this.user.bag = new Bag(10)`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.user.bag = new Bag(10);})Button(`ViewB: this.user = new User(new Bag(20))`).width(320).backgroundColor('#ff17a98d').margin(10).onClick(() => {this.user = new User(new Bag(20));})}}
}

效果图
在这里插入图片描述

被@Observed装饰的BookName类,可以观测到继承基类的属性的变化。


ViewB中的事件句柄:

  • this.user.bag = new Bag(10) 和this.user = new User(new Bag(20)): 对@State装饰的变量size和其属性的修改。
  • this.child.bookName.size += … :该变化属于第二层的变化,@State无法观察到第二层的变化,但是Bag被@Observed装饰,Bag的属性size的变化可以被@ObjectLink观察到。

ViewC中的事件句柄:

  • this.bookName.size += 1:对@ObjectLink变量size的修改,将触发Button组件的刷新。@ObjectLink和@Prop不同,@ObjectLink不拷贝来自父组件的数据源,而是在本地构建了指向其数据源的引用。
  • @ObjectLink变量是只读的,this.bookName = new bookName(…)是不允许的,因为一旦赋值操作发生,指向数据源的引用将被重置,同步将被打断。

八、对象数组

对象数组是一种常用的数据结构。以下示例展示了数组对象的用法。

let NextID: number = 1;@Observed
class Info {public id: number;public info: number;constructor(info: number) {this.id = NextID++;this.info = info;}
}@Component
struct Child {// 子组件Child的@ObjectLink的类型是Info@ObjectLink info: Info;label: string = 'ViewChild';build() {Row() {Button(`ViewChild [${this.label}] this.info.info = ${this.info ? this.info.info : "undefined"}`).width(320).margin(10).onClick(() => {this.info.info += 1;})}}
}@Entry
@Component
struct Parent {// Parent中有@State装饰的Info[]@State arrA: Info[] = [new Info(0), new Info(0)];build() {Column() {ForEach(this.arrA,(item: Info) => {Child({ label: `#${item.id}`, info: item })},(item: Info): string => item.id.toString())// 使用@State装饰的数组的数组项初始化@ObjectLink,其中数组项是被@Observed装饰的Info的实例Child({ label: `ViewChild this.arrA[first]`, info: this.arrA[0] })Child({ label: `ViewChild this.arrA[last]`, info: this.arrA[this.arrA.length-1] })Button(`ViewParent: reset array`).width(320).margin(10).onClick(() => {this.arrA = [new Info(0), new Info(0)];})Button(`ViewParent: push`).width(320).margin(10).onClick(() => {this.arrA.push(new Info(0))})Button(`ViewParent: shift`).width(320).margin(10).onClick(() => {if (this.arrA.length > 0) {this.arrA.shift()} else {console.log("length <= 0")}})Button(`ViewParent: item property in middle`).width(320).margin(10).onClick(() => {this.arrA[Math.floor(this.arrA.length / 2)].info = 10;})Button(`ViewParent: item property in middle`).width(320).margin(10).onClick(() => {this.arrA[Math.floor(this.arrA.length / 2)] = new Info(11);})}}
}

效果图
在这里插入图片描述

this.arrA[Math.floor(this.arrA.length/2)] = new Info(…) :该状态变量的改变触发2次更新:

  • ForEach:数组项的赋值导致ForEach的itemGenerator被修改,因此数组项被识别为有更改,ForEach的item builder将执行,创建新的Child组件实例。
  • Child({ label: ViewChild this.arrA[last], info: this.arrA[this.arrA.length-1] }):上述更改改变了数组中第二个元素,所以绑定this.arrA[1]的Child将被更新。

this.arrA.push(new Info(0)) : 将触发2次不同效果的更新:

  • ForEach:新添加的Info对象对于ForEach是未知的itemGenerator,ForEach的item builder将执行,创建新的Child组件实例。
  • Child({ label: ViewChild this.arrA[last], info: this.arrA[this.arrA.length-1] }):数组的最后一项有更改,因此引起第二个Child的实例的更改。对于Child({ label: ViewChild this.arrA[first], info: this.arrA[0] }),数组的更改并没有触发一个数组项更改的改变,所以第一个Child不会刷新。

this.arrA[Math.floor(this.arrA.length/2)].info:@State无法观察到第二层的变化,但是Info被@Observed装饰,Info的属性的变化将被@ObjectLink观察到。

九、二维数组

使用@Observed观察二维数组的变化。可以声明一个被@Observed装饰的继承Array的子类。

@Observed
class StringArray extends Array<string> {
}

使用new StringArray()来构造StringArray的实例,new运算符使得@Observed生效,@Observed观察到StringArray的属性变化。


声明一个从Array扩展的类class StringArray extends Array {},并创建StringArray的实例。@Observed装饰的类需要使用new运算符来构建class实例。

@Observed
class StringArray extends Array<string> {
}@Component
struct ItemPage {@ObjectLink itemArr: StringArray;build() {Row() {Text('ItemPage').width(100).height(100)ForEach(this.itemArr,(item: string | Resource) => {Text(item).width(100).height(100)},(item: string) => item)}}
}@Entry
@Component
struct IndexPage {@State arr: Array<StringArray> = [new StringArray(), new StringArray(), new StringArray()];build() {Column() {ItemPage({ itemArr: this.arr[0] })ItemPage({ itemArr: this.arr[1] })ItemPage({ itemArr: this.arr[2] })Divider()ForEach(this.arr,(itemArr: StringArray) => {ItemPage({ itemArr: itemArr })},(itemArr: StringArray) => itemArr[0])Divider()Button('update').onClick(() => {console.error('Update all items in arr');if ((this.arr[0] as StringArray)[0] !== undefined) {// 正常情况下需要有一个真实的ID来与ForEach一起使用,但此处没有// 因此需要确保推送的字符串是唯一的。this.arr[0].push(`${this.arr[0].slice(-1).pop()}${this.arr[0].slice(-1).pop()}`);this.arr[1].push(`${this.arr[1].slice(-1).pop()}${this.arr[1].slice(-1).pop()}`);this.arr[2].push(`${this.arr[2].slice(-1).pop()}${this.arr[2].slice(-1).pop()}`);} else {this.arr[0].push('Hello');this.arr[1].push('World');this.arr[2].push('!');}})}}
}

效果图
在这里插入图片描述

十、继承Map类

说明
从API version 11开始,@ObjectLink支持@Observed装饰Map类型和继承Map类的类型。

在下面的示例中,myMap类型为MyMap<number, string>,点击Button改变myMap的属性,视图会随之刷新。

@Observed
class Info {public info: MyMap<number, string>;constructor(info: MyMap<number, string>) {this.info = info;}
}@Observed
export class MyMap<K, V> extends Map<K, V> {public name: string;constructor(name?: string, args?: [K, V][]) {super(args);this.name = name ? name : "My Map";}getName() {return this.name;}
}@Entry
@Component
struct MapSampleNested {@State message: Info = new Info(new MyMap("myMap", [[0, "a"], [1, "b"], [3, "c"]]));build() {Row() {Column() {MapSampleNestedChild({ myMap: this.message.info })}.width('100%')}.height('100%')}
}@Component
struct MapSampleNestedChild {@ObjectLink myMap: MyMap<number, string>build() {Row() {Column() {ForEach(Array.from(this.myMap.entries()), (item: [number, string]) => {Text(`${item[0]}`).fontSize(30)Text(`${item[1]}`).fontSize(30)Divider().strokeWidth(5)})Button('set new one').width(200).margin(10).onClick(() => {this.myMap.set(4, "d")})Button('clear').width(200).margin(10).onClick(() => {this.myMap.clear()})Button('replace the first one').width(200).margin(10).onClick(() => {this.myMap.set(0, "aa")})Button('delete the first one').width(200).margin(10).onClick(() => {this.myMap.delete(0)})}.width('100%')}.height('100%')}
}

效果图
在这里插入图片描述

十一、继承Set类

说明
从API version 11开始,@ObjectLink支持@Observed装饰Set类型和继承Set类的类型。

在下面的示例中,mySet类型为MySet,点击Button改变mySet的属性,视图会随之刷新。

@Observed
class Info {public info: MySet<number>;constructor(info: MySet<number>) {this.info = info;}
}@Observed
export class MySet<T> extends Set<T> {public name: string;constructor(name?: string, args?: T[]) {super(args);this.name = name ? name : "My Set";}getName() {return this.name;}
}@Entry
@Component
struct SetSampleNested {@State message: Info = new Info(new MySet("Set", [0, 1, 2, 3, 4]));build() {Row() {Column() {SetSampleNestedChild({ mySet: this.message.info })}.width('100%')}.height('100%')}
}@Component
struct SetSampleNestedChild {@ObjectLink mySet: MySet<number>build() {Row() {Column() {ForEach(Array.from(this.mySet.entries()), (item: [number, number]) => {Text(`${item}`).fontSize(30)Divider()})Button('set new one').width(200).margin(10).onClick(() => {this.mySet.add(5)})Button('clear').width(200).margin(10).onClick(() => {this.mySet.clear()})Button('delete the first one').width(200).margin(10).onClick(() => {this.mySet.delete(0)})}.width('100%')}.height('100%')}
}

效果图
在这里插入图片描述

十二、ObjectLink支持联合类型

@ObjectLink支持@Observed装饰类和undefined或null组成的联合类型,在下面的示例中,count类型为Source | Data | undefined,点击父组件Parent中的Button改变count的属性或者类型,Child中也会对应刷新。

@Observed
class Source {public source: number;constructor(source: number) {this.source = source;}
}@Observed
class Data {public data: number;constructor(data: number) {this.data = data;}
}@Entry
@Component
struct Parent {@State count: Source | Data | undefined = new Source(10)build() {Column() {Child({ count: this.count })Button('change count property').onClick(() => {// 判断count的类型,做属性的更新if (this.count instanceof Source) {this.count.source += 1} else if (this.count instanceof Data) {this.count.data += 1} else {console.info('count is undefined, cannot change property')}})Button('change count to Source').onClick(() => {// 赋值为Source的实例this.count = new Source(100)})Button('change count to Data').onClick(() => {// 赋值为Data的实例this.count = new Data(100)})Button('change count to undefined').onClick(() => {// 赋值为undefinedthis.count = undefined})}.width('100%')}
}@Component
struct Child {@ObjectLink count: Source | Data | undefinedbuild() {Column() {Text(`count is instanceof ${this.count instanceof Source ? 'Source' :this.count instanceof Data ? 'Data' : 'undefined'}`).fontSize(30)Text(`count's property is  ${this.count instanceof Source ? this.count.source : this.count?.data}`).fontSize(15)}.width('100%')}
}

效果图
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/491427.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Excel拆分脚本

Excel拆分 工作表按行拆分为工作薄 工作表按行拆分为工作薄 打开要拆分的Excel文件&#xff0c;使用快捷键&#xff08;AltF11&#xff09;打开脚本界面&#xff0c;选择要拆分的sheet&#xff0c;打开Module&#xff0c;在Module中输入脚本代码&#xff0c;然后运行脚本 Su…

【机器人】Graspness 端到端 抓取点估计 | 论文解读

在复杂场景中实现抓取检测&#xff0c;Graspness是一种端到端的方法&#xff1b; 输入点云数据&#xff0c;输出抓取角度、抓取深度、夹具宽度等信息。 开源地址&#xff1a;GitHub - rhett-chen/graspness_implementation: My implementation of Graspnet Graspness. 论文地…

盛元广通畜牧与水产品检验技术研究所LIMS系统

一、系统概述 盛元广通畜牧与水产品检验技术研究所LIMS系统集成了检测流程管理、样品管理、仪器设备管理、质量控制、数据记录与分析、合规性管理等功能于一体&#xff0c;能够帮助实验室实现全流程的数字化管理。在水产、畜牧产品的质检实验室中&#xff0c;LIMS系统通过引入…

kubeadm安装K8s高可用集群之集群初始化及master/node节点加入calico网络插件安装

系列文章目录 1.kubeadm安装K8s高可用集群之基础环境配置 2.kubeadm安装K8s集群之高可用组件keepalivednginx及kubeadm部署 3.kubeadm安装K8s高可用集群之集群初始化及master/node节点加入集群calico网络插件安装 kubeadm安装K8s高可用集群之集群初始化及master/node节点加入ca…

【机器学习】以机器学习为翼,翱翔网络安全创新苍穹

我的个人主页 我的领域&#xff1a;人工智能篇&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;&#x1f44d;点赞 收藏❤ 在数字化浪潮汹涌澎湃的当下&#xff0c;网络安全如同守护数字世界的坚固堡垒&#xff0c;其重要性不言而喻。而机器学习技术的蓬勃…

go引用包生成不了vendor的问题

比如我要引入github.com/jinzhu/gorm这个包. 1. 首先获取包 go get github.com/jinzhu/gorm 这时go.mod文件中也有这个包依赖信息了. 2. 然后构建vendor go mod vendor 结果发现vendor目录下没有生成对应的包, 而且modules.txt也注释掉这个包了. 原因是没有其进行引用, go…

多模块的spring boot项目发布指定模块的脚本

我有一个多模块的Spring Boot项目&#xff0c;里面有基础模块&#xff0c;有业务模块&#xff0c;业务模块依赖一些基础模块。发布的时候&#xff0c;如果单独将某个模块发布&#xff0c;一般会报错。所以我都是整个项目&#xff0c;无论多少个模块&#xff0c;不管3721&#x…

fabric.js

目录 一、在canvas上画简单的图形 二、在canvas上用路径(Path)画不规则图形 三、在canvas上插入图片并设置旋转属性(angle) 四、让元素动起来(animate) 五、图像过滤器(filters)让图片多姿多彩 六、颜色模式(Color)和相互转换(toRgb、toHex) 七、对图形的渐变填充(Gradi…

23. 合并 K 个升序链表(java)

题目描述&#xff1a; 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]] 输出&#xff1a;[1,1,2,3,4,4,5,6] 解释&#xff…

爬取Q房二手房房源信息

文章目录 1. 实战概述2. 网站页面分析3. 编写代码爬取Q房二手房房源信息3.1 创建项目与程序3.2 运行程序&#xff0c;查看结果 4. 实战小结 1. 实战概述 本次实战项目旨在通过编写Python爬虫程序&#xff0c;抓取深圳Q房网上的二手房房源信息。我们将分析网页结构&#xff0c;…

【蓝桥杯】43699-四平方和

四平方和 题目描述 四平方和定理&#xff0c;又称为拉格朗日定理&#xff1a; 每个正整数都可以表示为至多 4 个正整数的平方和。如果把 0 包括进去&#xff0c;就正好可以表示为 4 个数的平方和。 比如&#xff1a; 502021222 712121222; 对于一个给定的正整数&#xff0c;可…

Kerberos身份验证

Kerberos是更现代化的身份验证协议&#xff0c;它比 NTLM 认证更安全&#xff0c;但域内某些服务仍支持 NTLM 认证。Kerberos 和 NTLM 认证一样&#xff0c;都是通过在 SSPI 接口实现的功能&#xff0c;这使得使用第三方协议&#xff08;如&#xff1a;HTTP、SMB、LDAP&#xf…

达梦8-达梦数据的示例用户和表

1、示例库说明&#xff1a; 创建达梦数据的示例用户和表&#xff0c;导入测试数据。 在完成达梦数据库的安装之后&#xff0c;在/opt/dmdbms/samples/instance_script目录下有用于创建示例用户的SQL文件。samples目录前的路径根据实际安装情况进行修改&#xff0c;本文将达梦…

认识javascript中的模块化

什么是模块化&#xff1f; 将程序⽂件依据⼀定规则拆分成多个文件&#xff0c;拆分出来每个⽂件就是⼀个模块&#xff0c;模块中的数据都是私有的&#xff0c;模块之间互相隔离。如果不进行隔离&#xff0c;可能会造成模块间的变量定义有冲突&#xff0c;导致程序崩溃 为啥要使…

EasyExcel 动态设置表格的背景颜色和排列

项目中使用EasyExcel把数据以excel格式导出&#xff0c;其中设置某一行、某一列单元格的背景颜色、排列方式十分常用&#xff0c;记录下来方便以后查阅。 1. 导入maven依赖&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>easy…

AccessClient在苹果电脑闪退,解决方法

AccessClient 2 年前突然闪退了&#xff0c;一直没管&#xff0c;最近弄一个 electron打包&#xff0c;一直提示找不到 python&#xff0c;解决了 python 解释器后&#xff0c;顺手把AccessClient闪退解决了&#xff0c;解决思路如下&#xff1a; 1.在AccessClient点击鼠标右…

NVM:安装配置使用(详细教程)

文章目录 一、简介二、安装 nvm三、配置 nvm 镜像四、配置环境变量五、使用教程5.1 常用命令5.2 具体案例 六、结语 一、简介 在实际的开发和学习中可能会遇到不同项目的 node 版本不同&#xff0c;而出现的兼容性问题。 而 nvm 就可以很好的解决这个问题&#xff0c;它可以在…

ActiveMQ 反序列化漏洞CVE-2015-5254复现

文章目录 一、产生原因二、利用条件三、利用过程四、PoC&#xff08;概念验证&#xff09;五、poc环境验证使用find搜索vulhub已安装目录打开activeMQ组件查看配置文件端口启动镜像-文件配置好后对于Docker 镜像下载问题及解决办法设置好镜像源地址&#xff0c;进行重启docker查…

【Python】【数据分析】深入探索 Python 数据可视化:Seaborn 可视化库详解

目录 引言一、Seaborn 简介二、安装 Seaborn三、Seaborn 的基本图形3.1 散点图&#xff08;Scatter Plot&#xff09;3.2 线图&#xff08;Line Plot&#xff09;3.3 条形图&#xff08;Bar Plot&#xff09;3.4 箱型图&#xff08;Box Plot&#xff09;3.5 小提琴图&#xff0…

某药业数据中心与重工集团灾备中心SAP监测实战应用

在当今数字化转型的浪潮中&#xff0c;企业的IT系统承载着前所未有的业务压力。作为业务运营的核心支撑&#xff0c;SAP系统的稳定性和性能优化成为运维团队关注的重点。本文将结合两个实际案例——某药业集团数据中心&#xff08;以下简称“药业数据中心”&#xff09;与某重工…