假期学习--对象底层结构和继承链

OC本质底层实现转化其实都是C/C++代码。

OC对象的本质就是结构体。

NSObject底层是struct objc_object结构体 ;

在这里插入图片描述

struct objc_class : objc_object {

…省略无关代码

// Class ISA; //ISA(从objc_object继承过来的)

Class superclass; //指向其父类

cache_t cache; //缓存

class_data_bits_t bits; //类的数据

…省略无关代码

}

objc_class是继承objc_object的。

  • 每个类的底层都会有一个Class类的isa指针。
  • Class底层是struct objc_class *类型,NSObject底层是struct objc_object结构体,id底层是struct objc_object *类型。

NSObject底层实现的结构体里只有一个成员变量isa,又因为Class底层是struct objc_class *类型,所以 ***\*NSObject\*****的本质是****\*objc_class\****
可以看到gettersetter里是通过****首地址指针+对应成员变量的地址值指针的偏移量*的方式取和存的,最终通过(*(NSString **)还原为string类型。取值的过程就是:*先拿到当前成员变量的地址,再去取这个地址里面所存的值****。

objc_class 和 objc_object 有什么关系?

objc_object

objc_object是一个结构体,它代表了一个Objective-C中的对象实例。这个结构体中最重要的成员是isa指针,它指向对象所属的类(objc_class类型的指针)。isa的存在使得运行时系统能够识别对象的类型,并调用正确的类方法或实例方法。

objc_class

objc_class也是一个结构体,它描述了一个类的特性,包括其父类、方法列表、属性列表、协议列表、成员变量列表等。每个类都有一个对应的objc_class实例,这个实例包含了该类的全部元数据和行为信息。

objc_class继承自objc_object,也就是说objc_class本身也是objc_object的一种,具有isa指针。这意味着类本身也可以被视为对象,能够接收消息。此外,objc_classisa指针指向的是它的元类(Meta-Class),而元类负责存储类方法。

关系总结

  • objc_object是Objective-C中所有对象的基础结构,它允许运行时系统识别和操作对象。
  • objc_class描述了一个类的结构和行为,它本身也是objc_object的一种特殊形式,意味着类也可以被当作对象来对待。
  • 每个objc_object实例都有一个isa指针,指向其所属的objc_class
  • 每个objc_class实例也有一个isa指针,但它指向的是该类的元类,元类中包含了类方法。

通过这种方式,Objective-C实现了动态类型和动态绑定,允许在运行时根据对象的实际类型调用适当的方法。这种机制是Objective-C动态特性的基石,也是其与静态类型语言的主要区别之一。

补充:

objc_class继承自objc_objectobjc_object有isa属性,所以对象都有一个isa,isa 表示指向,来自于当前的objc_object

objc_object与对象的关系:
  • 所有对象都是以objc_object为模板继承过来的。
  • 所有对象都来自于NSObject,但是其底层是一个objc_object的结构体类型,所以objc_object与对象的关系是继承关系。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=%2FUsers%2Fzhujingye%2FLibrary%2FContainers%2Fcom.yinxiang.Mac%2FData%2Ftmp%2Fcom.yinxiang.Mac%2FWebKitDnD.d2mNGh%2F7603BF5A-554A-4E80-B39C-E62C39943ECF.png&pos_id=img-yQ5SpFXm-172482600141

类结构

在这里插入图片描述

上面是runtime中的类结构关系图 ;

类是一个结构体,大致如下:

struct objc_class : objc_object {...省略无关代码// Class ISA;  //ISA(从objc_object继承过来的)Class superclass;  //指向其父类cache_t cache;  //缓存class_data_bits_t bits;  //类的数据class_rw_t *data() const {return bits.data();}void setData(class_rw_t *newData) {bits.setData(newData);}...省略无关代码
}  

3234234

继承自objc_object的isa指针,不仅实例对象中有,类对象中也有,占8字节。

isa指针的指向

对于每个类创建出来的对象都会默认有一个isa属性,保存类对象的地址,也就是class,通过class就可以查询到这个对象的属性和方法,协议等;

对于类来说,它的类对象就是其元类 ;

isa分两种类型(isa指针是什么含义的时候):

  • 指针型isa:64位的0或者1的整体内容代表所指向的Class的地址,也就是可以通过isa的内容来获得类对象的地址。
    • 非指针型isa:isa的值的部分代表Class的地址,之所以这样是因为我们在寻址过程中,只有三四十位数就可以保证我们寻找到所有Class地址了,多出来的位可以用来存储其他相关内容,来达到节省内存的目的。

isa的数据结构

每个OC对象都含有一个isa指针,__arm64__之前,isa仅仅是一个指针,保存着对象或类对象内存地址,在__arm64__架构之后,apple对isa进行了优化,变成了一个共用体(union)结构,同时使用位域来存储更多的信息。

union isa_t 
{Class cls;uintptr_t bits;struct {uintptr_t nonpointer        : 1;//->表示使用优化的isa指针uintptr_t has_assoc         : 1;//->是否包含关联对象uintptr_t has_cxx_dtor      : 1;//->是否设置了析构函数,如果没有,释放对象更快uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000 ->类的指针uintptr_t magic             : 6;//->固定值,用于判断是否完成初始化uintptr_t weakly_referenced : 1;//->对象是否被弱引用uintptr_t deallocating      : 1;//->对象是否正在销毁uintptr_t has_sidetable_rc  : 1;//1->在extra_rc存储引用计数将要溢出的时候,借助Sidetable(散列表)存储引用计数,has_sidetable_rc设置成1uintptr_t extra_rc          : 19;  //->存储引用计数,实际的引用计数减一,存储的是其对象以外的引用计数};
};

初始化isa(其实就是上面两种不同的isa指针初始化也不一样)

  • 通过cls初始化:
    nonpointer,存储着ClassMeta-Class对象的内存地址信息。
  • 通过bits初始化:
    nonpointer,进行一系列的初始化操作。

superclass

superclass指向该对象或该类的父类

cache

45345345

引入了bucket_t(散列表数组),cache_t哈希表结构,哈希表内部存储的bucket_tbucket_t中存储的是SELIMP的键值对。

(这里就是消息传递刚开始查找方法所在的缓存)

img

bits

class_data_bits_t作为属性bits的类型,也是个结构体

struct class_data_bits_t {friend objc_class;//这里声明objc_class为class_data_bits_t的友元类,使得objc_class可以访问class_data_bits_t中的私有方法uintptr_t bits;......

结构体中的属性bits是无符号整数类型,能够存储指针。这通常意味着它与指针的大小相同。

这里面其实利用位域存储数据,简单来说因为这个bits跟指针大小相同,在iOS中指针大小是8个字节,也就是64位,但是通常单一数据无法用满这64位的,会有很多空位,造成空间浪费。通过位运算,把不同的数据按不同的位置存进这64位内存空间的不同位置里,这样就可以提高内存利用率。这里的bits其实就是这样的,他不只存储class_rw_t结构体指针,还存储其他的信息。所以这里的bits并不是结构体,而是一个无符号整数类型的指针 ;

对于类的方法列表,成员列表的等信息则存放在bits更深一层的class_rw_t指针里面

class_rw_t

4234234

protocols类分类中的协议

properties类分类中的属性

methods类分类中的方法

这三个数据结构是个二维数组

假如我们三个分类A、B、C,编译顺序A->B->C。这时会逆序遍历并打包成分类数组,分类C中的所有方法都在第一列竖列表中,存在二维数组的第1项。分类B中的所有方法都在第二列竖列表中,存在二维数组的第2项。分类A中的所有方法都在第三列竖列表中,存在二维数组的第3项。

总结:这个二维数组的每一项对应一个category所增加的方法 ;结合之后了解到的,也可以知道,这个二微数组中的方法都是在运行时动态添加的

下面是有关class_rw_t的源码:

struct class_rw_t {// Be warned that Symbolication knows the layout of this structure.uint32_t flags;uint16_t witness;
#if SUPPORT_INDEXED_ISAuint16_t index;
#endifexplicit_atomic<uintptr_t> ro_or_rw_ext;Class firstSubclass;Class nextSiblingClass;
private:using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t *, class_rw_ext_t *>;const ro_or_rw_ext_t get_ro_or_rwe() const {return ro_or_rw_ext_t{ro_or_rw_ext};}void set_ro_or_rwe(const class_ro_t *ro) {ro_or_rw_ext_t{ro}.storeAt(ro_or_rw_ext, memory_order_relaxed);}void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) {// the release barrier is so that the class_rw_ext_t::ro initialization// is visible to lockless readersrwe->ro = ro;ro_or_rw_ext_t{rwe}.storeAt(ro_or_rw_ext, memory_order_release);}class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
public:void setFlags(uint32_t set){__c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED);}void clearFlags(uint32_t clear) {__c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED);}// set and clear must not overlapvoid changeFlags(uint32_t set, uint32_t clear) {ASSERT((set & clear) == 0);uint32_t oldf, newf;do {oldf = flags;newf = (oldf | set) & ~clear;} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));}class_rw_ext_t *ext() const {return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>();}class_rw_ext_t *extAllocIfNeeded() {auto v = get_ro_or_rwe();if (fastpath(v.is<class_rw_ext_t *>())) {return v.get<class_rw_ext_t *>();} else {return extAlloc(v.get<const class_ro_t *>());}}class_rw_ext_t *deepCopy(const class_ro_t *ro) {return extAlloc(ro, true);}const class_ro_t *ro() const {auto v = get_ro_or_rwe();if (slowpath(v.is<class_rw_ext_t *>())) {return v.get<class_rw_ext_t *>()->ro;}return v.get<const class_ro_t *>();}void set_ro(const class_ro_t *ro) {auto v = get_ro_or_rwe();if (v.is<class_rw_ext_t *>()) {v.get<class_rw_ext_t *>()->ro = ro;} else {set_ro_or_rwe(ro);}}######const method_array_t methods() const {auto v = get_ro_or_rwe();if (v.is<class_rw_ext_t *>()) {return v.get<class_rw_ext_t *>()->methods;} else {return method_array_t{v.get<const class_ro_t *>()->baseMethods()};}}const property_array_t properties() const {auto v = get_ro_or_rwe();if (v.is<class_rw_ext_t *>()) {return v.get<class_rw_ext_t *>()->properties;} else {return property_array_t{v.get<const class_ro_t *>()->baseProperties};}}const protocol_array_t protocols() const {auto v = get_ro_or_rwe();if (v.is<class_rw_ext_t *>()) {return v.get<class_rw_ext_t *>()->protocols;} else {return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};}}
};

对于最后三个方法,我们可以从名称大致猜到他们和保存的方法列表,属性列表和协议列表有关 ;

const method_array_t methods()为例,获取类的实例方法也是通过调用methods()来获取的。比如说runtime函数class_copyMethodList,其代码如下:

Method *
class_copyMethodList(Class cls, unsigned int *outCount)
{unsigned int count = 0;Method *result = nil;if (!cls) {if (outCount) *outCount = 0;return nil;}mutex_locker_t lock(runtimeLock);const auto methods = cls->data()->methods(); /ASSERT(cls->isRealized());count = methods.count();if (count > 0) {result = (Method *)malloc((count + 1) * sizeof(Method));count = 0;for (auto& meth : methods) {result[count++] = &meth;}result[count] = nil;}if (outCount) *outCount = count;return result;
}

对于上面的const auto methods = cls->data()->methods();,这里调用了methods()方法获取了方法列表 ,也就是class_rw_t中的const method_array_t methods() 方法 ;但我们在观察class_rw_t时却在其结构中找不到存储方法列表的属性,从const method_array_t methods() 方法 中我们可以发现对方法列表的读取是在class_rw_ext_t和class_ro_t指针中进行的 ;

class_rw_ext_t

class_rw_ext_t是个结构体,其数据结构如下:

struct class_rw_ext_t {const class_ro_t *ro;method_array_t methods;property_array_t properties;protocol_array_t protocols;char *demangledName;uint32_t version;
};

由此可知,结构体class_rw_ext_t中的确有方法列表、属性列表和协议等信息,而且还有一个class_ro_t指针,接下来继续看class_ro_t

class_ro_t

4324234

以下是class_ro_t的结构体:

struct class_ro_t {uint32_t flags;uint32_t instanceStart;uint32_t instanceSize;
#ifdef __LP64__uint32_t reserved;
#endifconst uint8_t * ivarLayout;const char * name;method_list_t * baseMethodList;protocol_list_t * baseProtocols;const ivar_list_t * ivars;const uint8_t * weakIvarLayout;property_list_t *baseProperties;// This field exists only when RO_HAS_SWIFT_INITIALIZER is set._objc_swiftMetadataInitializer __ptrauth_objc_method_list_imp _swiftMetadataInitializer_NEVER_USE[0];_objc_swiftMetadataInitializer swiftMetadataInitializer() const {if (flags & RO_HAS_SWIFT_INITIALIZER) {return _swiftMetadataInitializer_NEVER_USE[0];} else {return nil;}}method_list_t *baseMethods() const {return baseMethodList;}class_ro_t *duplicate() const {if (flags & RO_HAS_SWIFT_INITIALIZER) {size_t size = sizeof(*this) + sizeof(_swiftMetadataInitializer_NEVER_USE[0]);class_ro_t *ro = (class_ro_t *)memdup(this, size);ro->_swiftMetadataInitializer_NEVER_USE[0] = this->_swiftMetadataInitializer_NEVER_USE[0];return ro;} else {size_t size = sizeof(*this);class_ro_t *ro = (class_ro_t *)memdup(this, size);return ro;}}
};

这里面我们发现class_ro_t不仅有baseMethodList、 baseProtocols、baseProperties等信息,还有成员变量const ivar_list_t * ivars等其他信息。在了解他们的结构之后,我们从结构上简单做一下它们之间关系的分析:

  • 首先class_rw_t有一个指针ro_or_rw_ext,ro_or_rw_ext指向可能是class_rw_ext_t或者是class_ro_t。ro_or_rw_ext指针的作用是,当读取类相关信息时,会优先判断是否指向class_rw_ext_t,如果是class_rw_ext_t就从它读取,没有就是class_ro_t,直接从class_ro_t读取。

    那么在程序运行中到底ro_or_rw_ext什么时候是class_rw_ext_t,什么时候是class_ro_t呢?

class_ro_t & class_rw_t & class_rw_ext_t & Class之间的关系

从字面意思解读class_ro_t中的“ro”代表只读;class_rw_t中的“rw”代表可读可写;class_rw_ext_t中的“rw_ext”代表可读可写的扩展。
干净内存和脏内存:干净内存内存指的是内存一旦加载就不会被改变。反之,脏内存就是在运行时会被修改的。

Class本身是运行时加载的,在运行时会被改变,所以本身Class就是属于脏内存。那么如果想要获取Class的干净内存,也就是编译时确定的数据结构包括方法列表、成员变量等的,该怎么办?
这其实就是class_ro_t的作用。因为class_ro_t是只读,意味着 class_ro_t是从mach-o读取类的数据之后,就不会被改变。那如果我们想在运行时修改类的信息,比如添加方法,比如加载category怎么办呢?那这时候就有一个与之对应的class_rw_t结构,class_rw_t可以在运行时存储类的信息,可读可写的,可以在运行时修改。
说到这里,好像还漏掉一个结构class_rw_ext_t,这个东西又是干什么用的呢?存在的意义是什么?其实还是跟运行时有关。实际上在我们的app运行中,需要运行时修改的类是非常少的,据统计平均大概就10%左右。那也就是说大部分只需要读取class_ro_t中的数据就够了,少部分才需要修改。因此才会有class_rw_ext_t这个扩展的结构体。class_rw_ext_t的作用是这样的:当我们需要修改类结构时,比如添加方法、加载category等时,class_rw_t回去开辟一个额外的空间rwe(class_rw_ext_t),用于存储新的方法和class_ro_t中的方法等信息。这样做的目的有一个好处就是,对于绝大部分类是不需要这个开辟class_rw_ext_t这个结构体,节省内存。

创建时机

*那这几个结构分别是什么时候创建的呢?这里就设计到类的加载流程。首先类在app启动的时候会被映射到内存,这时候会先创建Class(objc_class)结构,然后把类编译时的类数据映射到class_ro_t,class_ro_t结构体指针存储到Class的bits指针中,我们前面提到类的bits中存储的是class_rw_t指针,实际上在类初始化之前这里存储的是class_ro_t,等到类初始化的时候会创建一个class_rw_t结构,然后通过data()从bits中读取class_ro_t,然后class_rw_t通过set_ro(const class_ro_t ro)把指针ro_or_rw_ext指向这个class_ro_t,然后Class通过setData()把class_rw_t指针存储到bits里面。然后在运行时根据需要,根据extAllocIfNeeded或extAlloc创建class_rw_ext_t,然后把class_ro_t关联到class_rw_ext_t

上面的解读也可以说明下面的一些问题了:

category不能添加成员变量的原因

因为category是运行时添加的,他只能操作class_rw_t结构,但是class_rw_t结构没有添加成员变量的入口。成员变量是存储在class_ro_t中的,是无法被修改的,所以category就不能添加成员变量。

类数据的存储结构

4324234

4324234

对于上面的class_rw_t中实际上找不到对应的methods属性,所以更像是调用方法从而直接获取对应的数组,同理其他也应该是这样的 ;

继承者链

示例:

  • 继承自NSObject的类LGPerson
  • 继承自LGPerson的类LGTeacher
  • main中分别用两个定义两个对象:personteacher
int main(int argc, const char * argv[]) {@autoreleasepool {LGPerson *person = [[LGPerson alloc] init];LGTeacher *teacher = [[LGTeacher alloc] init];NSLog(@"Hello, World! %@ - %@", person, teacher);}return 0;
}
  • mainLGTeacher部分加一个断点,运行程序。
  • 开启lldb调试,调试的过程如下图所示。
  • 5345345

0x0100000100008239是person对象的isa指针地址,其&后得到的结果是创建person的类LGPerson。
0x0000000100008210是isa中获取的类信息所指的类的isa的指针地址,即LGPerson类的类的isa指针地址,在Apple中,我们简称LGPerson类的类为元类。
所以,两个打印都是LGPerson的根本原因就是因为元类导致的。

元类是什么

  • 我们都知道对象的isa是指向类,类的其实也是一个对象,可以称为类对象,其isa的位域指向苹果定义的元类。
  • 元类是系统给的,其定义和创建都是由编译器完成,在这个过程中,类的归属来自于元类。
  • 元类是类对象 的类,每个类都有一个独一无二的元类用来存储类方法的相关信息。
  • 元类本身是没有名称的,由于与类相关联,所以使用了同类名一样的名称。

简单的总结一下,元类是没有名称的类(使用了同类名一样的名称),是类对象的isa指针所指向的类 ;

img

对象 --> 类 --> 元类 --> NSobject,NSObject指向自身。

对于NSobject,NSObject(根元类)在内存中永远只存在一份,由于类的信息在内存中永远只存在一份,所以类对象只有一份。

著名的isa走位 & 继承关系图

5345345345

isa走位

实例对象(Instance of Subclass)的isa指向类(class)
类对象(class)的isa指向元类(Meta class)
元类(Meta class)的isa指向根元类(Root metal class)
根元类(Root metal class)的isa指向它自己本身,形成闭环,这里的根元类就是NSObject

superclass走位

类之间的继承关系:

类(subClass)继承自父类(superClass)
父类(superClass)继承自根类(RootClass),此时的根类是指NSObject
根类继承自nil,所以根类即NSObject可以理解为万物起源,即无中生有
元类也存在继承,元类之间的继承关系如下:

子类的元类(metal SubClass)继承自父类的元类(metal SuperClass)
父类的元类(metal SuperClass)继承自根元类(Root metal Class)
根元类(Root metal Class)继承于根类(Root class),此时的根类是指NSObject
【注意】实例对象之间没有继承关系,类之间有继承关系。

对象方法,属性,成员变量,协议信息 存放在class对象中。
类方法,存放在meta-class对象中。
成员变量的具体值,存放在instance对象中。

https://blog.csdn.net/m0_55124878/article/details/125808836

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

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

相关文章

旅游行业怎么利用C#接口发送短信

旅游企业一般拥有众多的分支机构&#xff0c;同时各地分支机构又有众多下属分散在当地各区的旅游营业报名点&#xff0c;以前传统的解决方案是采用专线、MODEM拔号等方式&#xff0c;专线的成本很高&#xff0c;MODEM拔号更费时&#xff0c;且长途拔号互联成本在多点情况下费用…

微前端集成优化:让所有子应用体积更小,加载更快!

简介 随着前端的日益发展&#xff0c;微前端架构越来越受到青睐。它通过将前端应用拆分为多个独立的子应用&#xff0c;每个子应用可以独立开发、部署和运行&#xff0c;从而提升了开发效率和团队协作。目前主流的微前端方案应该是qiankun了。 以笔者公司为例&#xff0c;采用…

基于SpringBoot的在线答疑系统

你好呀&#xff0c;我是计算机专业毕业生&#xff0c;专注于在线教育平台的开发与实现。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术 Spring Boot框架 工具&#xff1a;IntelliJ IDEA、Navicat、Maven、Tomcat 系统展示 首页 个人中心…

scrapy--图片管道-ImagesPipeline

免责声明:本文仅做演示与分享~ 目录 介绍 ImagesPipeline pipelines.py items.py zz.py settings.py 介绍 scrapy 还提供了处理图片、视频、音频等媒体文件的插件&#xff0c;如&#xff1a; - scrapy-images&#xff1a;用于下载和处理图片 - scrapy-video&#xff1…

责任链设计模式详解

责任链设计模式详解 一、定义 责任链设计模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为设计模式&#xff0c;它允许多个对象有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合。这种模式将这些对象连接成一条链&#xff0c;并沿着…

提前还房贷结果失败了该怎么办?需要注意哪些?怎么做更顺利?

提前还房贷结果失败了&#xff0c;该怎么办&#xff1f; 1. 满足条件再申请&#xff1a;部分银行对提前还款设有一定的条件和限制&#xff0c;例如需要提前预约&#xff0c;对已还款时间和还款金额也有具体的要求。如果借款人未能满足这些条件&#xff0c;提前还款的申请可能会…

【精选】计算机毕业设计之:基于springboot超市进销存系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Stable Diffusion AI绘画工具的安装与配置(MAC用户)

AI绘画的热潮席卷了整个创意行业&#xff0c;Stable Diffusion作为其中的翘楚&#xff0c;让艺术创作变得前所未有的简单。然而&#xff0c;对于使用Mac电脑用户来说&#xff0c;安装和配置Stable Diffusion可能显得有些棘手。别担心&#xff0c;这份详细的教程将手把手教你如何…

【Material-UI】Select 组件中的 `Auto width`、`Small Size` 和 `Other Props` 详解

文章目录 一、Select 组件概述1. 组件介绍2. Select 组件的基本结构 二、Auto width 属性详解1. Auto width 的作用2. Auto width 属性的基本用法3. Auto width 的实际应用场景 三、Small Size 属性详解1. Small Size 的作用2. Small Size 属性的基本用法3. Small Size 的实际应…

Windows怎么让防火墙开放端口

开放端口的方法 先从控制面板,进入到Windows Defender防火墙 点击高级设置,点击入站规则 点击右边的新建规则,点击端口,点击下一步 选择协议类型和端口号点击下一步即可 查看是否开放端口成功的方法: 进入任务管

【rk3588】环境搭建及系统编译

开发板&#xff1a;ROC-RK3588S-PC 官方链接&#xff1a;Welcome to ROC-RK3588S-PC Manual — Firefly Wiki (t-firefly.com) 串口调试配置 一、产品介绍 — Firefly Wiki (t-firefly.com)&#xff0c;可以按照官方链接的说明在个人PC上使用串口。这个串口会输出rk3588的日…

【Python机器学习】NLP词频背后的含义——从词频到主题得分

目录 TF-IDF向量及词形归并 主题向量 一个思想实验 一个主题评分算法 一个LDA分类器 LDiA TF-IDF向量&#xff08;词项频率—逆文档频率向量&#xff09;可以帮助我们估算词在文本块中的重要度&#xff0c;我们使用TF-IDF向量和矩阵可以表明每个词对于文档集合中的一小段…

计算机视觉编程 1(图片处理)

目录 灰色度 缩略图 拷贝粘贴区域 调整图像尺寸 旋转图像45 画图线、描点 灰色度 灰度是指图像中每个像素的亮度值&#xff0c;用来描述图像中各个像素的明暗程度。在计算机视觉中&#xff0c;灰度可以通过以下方式来计算&#xff1a; 1. 平均值法&#xff1a;将图像中每…

Java基础——自学习使用(泛型)

一、泛型的定义 泛型的本质是参数化类型&#xff0c;也就是所操作的数据类型被指定为一个参数。 泛型泛指一切类型&#xff0c;能够代表一切类型&#xff0c;是一种在编程中广泛使用的概念&#xff0c;特别是在面向对象编程中。它允许在编写代码时使用类型参数&#xff0c;这些…

MES管理系统助力印刷企业实现智能化工艺流程

在印刷这一古老而充满活力的行业中&#xff0c;科技的浪潮正以前所未有的速度重塑着每一个生产环节。随着制造业数字化转型的深入&#xff0c;引入MES管理系统&#xff0c;为印刷企业带来了从原材料入库到成品出库的全流程智能化变革&#xff0c;不仅提升了生产效率&#xff0c…

剪辑小白必看:好用的剪辑工具推荐!

作为一位热爱创作的视频制作者&#xff0c;我尝试过不少剪辑软件&#xff0c;今天我想分享自己对福昕视频剪辑、爱拍剪辑、达芬奇和VSDC Video Editor这四款软件的使用体验。 福昕视频剪辑 链接&#xff1a;www.pdf365.cn/foxit-clip/ 我第一次接触到福昕视频剪辑是在朋友的…

树数据结构(Tree Data Structures)的全面指南:深度解析、算法实战与应用案例

树数据结构&#xff08;Tree Data Structures&#xff09;的全面指南&#xff1a;深度解析、算法实战与应用案例 引言 树数据结构&#xff08;Tree Data Structures&#xff09;作为计算机科学中的基石之一&#xff0c;以其独特的层次结构和分支特性&#xff0c;在众多领域发…

2012-2022年各省新质生产力匹配数字经济数据

2012-2022年各省新质生产力匹配数字经济数据 1、时间&#xff1a;2012-2022年 2、来源&#xff1a;各省年鉴、能源年鉴、工业年鉴、统计年鉴 3、指标&#xff1a;prov、year、gdp亿元、在岗职工工资元、第三产业就业比重、人均受教育平均年限、教育经费强度、在校学生结构、…

【STM32】IWDG独立看门狗与WWDG窗口看门狗

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 WDG简介 IWDG IWDG特性 独立看门狗时钟 键寄存器 超时时间 IWDG代码 WWDG WWDG特性 窗口看门狗时钟 超时时间 WWDG时序 WWDG代码 IWDG和WWDG对比 WDG简介 WDG&#xff08;…

面经:什么是Transformer位置编码?

过去的几年里&#xff0c;Transformer大放异彩&#xff0c;在各个领域疯狂上分。它究竟是做什么&#xff0c;面试常考的Transformer位置编码暗藏什么玄机&#xff1f;本文一次性讲解清楚。 Transformer的结构如下&#xff1a; 可能是NLP界出镜率最高的图 Transformer结构中&a…