unordered_map与unordered_set的实现(含迭代器)

unordered_map与unordered_set的实现


文章目录

  • unordered_map与unordered_set的实现
  • 前言
  • 一、问题一
    • HashTable.h
  • 二、问题二&问题三
    • 1.封装时如何取出key
    • 2.不同类型key如何建立对应关系
  • 三、问题四&问题五
    • 问题四
    • 问题五
  • 四、实现代码
    • MyUnorderedSet.h
    • MyUnorderedMap.h
    • HashTable.h


前言

在C++11中新增了两个很好用的容器,分别是unordered_map与unordered_set,和map和set有不同之处

map与set的底层实现是平衡树——红黑树,并且采取中序遍历时默认有序

而本文的unordered_map与unordered_set底层实现是哈希思想(拉链法),并且他的存储方式不支持排序,所以是unordered

两者的查找效率综合比较,会发现unordered_map与unordered_set的效率综合会更高,所以在C++11中支持了unordered_map与unordered_set

本文中是用哈希桶的拉链法来封装unordered_map与unordered_set
这里的封装与红黑树封装map和set的封装相似,但此处会更难

具体通过解决问题来实现

  1. HashTable的迭代器实现
  2. 封装时HashTable如何取出map的key和set的key
  3. 取出key后如何针对不同类型key建立映射关系
  4. 如何解决Set中key不能被修改,Map中key不能被修改,value能被修改的问题
  5. Insert插入返回值问题以及Map[]的重载实现

关于哈希思想及其具体实现细节看我的上篇文章:数据结构之哈希表


一、问题一

这里就一步步,先实现iterator再实现const_iterator版本了,而是直接放出能适配iterator与const_iterator的版本,本质上就是用类模板泛型编程,需要什么就调用什么,是什么类型就返回什么类型的迭代器

这里尤为注意的一点是,这里的迭代器是单向迭代器,只支持++,而由于底层是哈希表的拉链法实现的,是数组与链表结合的方式
在实现运算符重载++时,本质上就是在逐个遍历哈希桶,而当前桶走完的时候,需要进入下一个桶,那么如何判断当前桶的位置,以及如何找到下一个桶,就需要把这个数组或者整个哈希表传过来,这里我们做的是把整个哈希表传过来

注意:其实将数组传过来会更简单些,传哈希表会有一些问题

  1. 我们将哈希表传过来,是可能要访问哈希表内的私有变量来获得下一个桶,而直接在_HTIterator这个类内使用哈希表内的私有变量是不可取的,所以需要在哈希表内声明友元
  2. 此处还涉及编译问题,由于编译器是从上往下编译代码,我们将迭代器写在哈希表代码的上面,而迭代器中有哈希表,这里编译器并不认识哈希表,因为哈希表的定义还未出现,所以还需要哈希表对应的类的声明
	template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct _HTIterator;
	template<class K, class T, class KeyOfT, class Hash>class HashTable;

至于class KeyOfT 与 class Hash这两个类模板的作用,则在下文中解答

HashTable.h

namespace hash_bucket
{template<class T>struct HashNode{HashNode(const T& data):_data(data),_next(nullptr){}T _data;HashNode* _next;};template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>struct _HTIterator{typedef HashNode<T> Node;typedef _HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;_HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht):_node(node),_pht(pht){}_HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht):_node(node), _pht(pht){}_HTIterator(const iterator& x):_node(x._node), _pht(x._pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self operator++(){Hash hf;KeyOfT kot;size_t hashi = hf(kot(_node->_data)) % _pht->_t.size();if (_node->_next != nullptr){_node = _node->_next;}else{hashi++;while (hashi < _pht->_t.size()){if (_pht->_t[hashi]){_node = _pht->_t[hashi];break;}hashi++;}}if (hashi == _pht->_t.size()){_node = nullptr;}return *this;}bool operator==(const Self& it){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}const HashTable<K, T, KeyOfT, Hash>* _pht;Node* _node;};template<class K, class T, class KeyOfT, class Hash>class HashTable{typedef HashNode<T> Node;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct _HTIterator;public:HashTable(size_t n = 10){_t.resize(n);}typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;typedef _HTIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;iterator begin(){size_t hashi = 0;while (hashi < _t.size()){if (_t[hashi]){break;}hashi++;}if (hashi == _t.size()){return iterator(nullptr, this);}return iterator(_t[hashi], this);}iterator end(){return iterator(nullptr, this);}const_iterator begin()const{size_t hashi = 0;while (hashi < _t.size()){if (_t[hashi]){break;}hashi++;}if (hashi == _t.size()){return iterator(nullptr, this);}return iterator(_t[hashi], this);}const_iterator end()const{return iterator(nullptr, this);}pair<iterator,bool> Insert(const T& data){KeyOfT kot;Hash hf;iterator ret = Find(kot(data));if (ret != end()){return make_pair(ret, false);}//扩容if (_n / _t.size() == 1){size_t newsize = _t.size() * 2;HashTable newtable(newsize);for (int i = 0; i < _n; i++){Node* cur = _t[i];while (cur){Node* next = cur->_next;size_t hashi = hf(kot(cur->_data)) % newsize;cur->_next = newtable._t[hashi];newtable._t[hashi] = cur;cur = next;}_t[i] = nullptr;}swap(_t, newtable._t);}size_t  hashi = hf(kot(data)) % _t.size();Node* newnode = new Node(data);newnode->_next = _t[hashi];_t[hashi] = newnode;_n++;return make_pair(iterator(newnode, this), true);}iterator Find(const K& key){Hash hf;KeyOfT kot;size_t hashi = hf(key) % _t.size();Node* cur = _t[hashi];while (cur){if (kot(cur->_data) == key){return iterator(cur, this);}cur = cur->_next;}return iterator(nullptr, this);}bool Erase(const K& key){Hash hf;KeyOfT kot;size_t hashi = hf(key) % _t.size();Node* cur = _t[hashi];Node* prev = nullptr;if (kot(cur->_data) == key){_t[hashi] = cur->_next;delete cur;return true;}while (cur){if (kot(cur->_data) == key){prev->_next = cur->_next;delete cur;_n--;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<HashNode<T>*> _t;size_t _n = 0;};
}

二、问题二&问题三

1.封装时如何取出key

首先解释一下问题,我们的目的是将unordered_map与unordered_set用哈希表封装实现,map中存的是pair,set中存的是key,而如何用一份哈希表适配两种结构呢

在封装的时候解决这个问题,在unordered_map与unordered_set中写一个内部类,这个类之中实现了一个仿函数,用来返回key,并且将其传给哈希表内

	template<class K, class V, class Hash = HashFunc<K>>class unordered_map{public:struct KeyOfT{const K& operator()(const pair<K, V>& kv){return  kv.first;}};private:hash_bucket::HashTable<K, pair<const K, V>, KeyOfT, Hash> _ht;};
template<class K, class Hash = HashFunc<K>>class unordered_set{public:struct KeyOfT{const K& operator()(const K& key){return  key;}};private:hash_bucket::HashTable<K, K, KeyOfT, Hash> _ht;};

2.不同类型key如何建立对应关系

本文的拉链法中,使用的哈希函数是除留余数法,如果key是int类型的话那正好,可以直接用key除,但如果key是string或者自定义类型,那么就不能够直接除了,则需要将其转换成int类型,另外一个模板参数Hash,则是将其转换方式传给哈希表

如果是内置类型的float,double之类的,我们可以直接强转成size_t返回
如果是string类型,由于string比较常用,我们可以为string搞个特化,默认支持string

上面两个都是默认支持的,用默认缺省值就行,不需要手动传Hash

而如果是自定义类型,则需要使用者通过接口手动传Hash,因为默认的缺省值用不了

template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};template<>
struct HashFunc<string>
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){hash *= 13;hash += e;}return hash;}
};

三、问题四&问题五

问题四与问题五与set与map用红黑树封装的问题相同

问题四

set的iterator和const_iterator都是红黑树的const_iterator复用而来
map中的iterator是红黑树的iterator复用而来,const_iterator是红黑树的const_iterator复用而来
既然set中的迭代器都是const_iterator所以key自然不能被修改

	typedef typename hash_bucket::HashTable<K, K, KeyOfT, Hash>::const_iterator iterator;typedef typename hash_bucket::HashTable<K, K, KeyOfT, Hash>::const_iterator const_iterator;

map解决key不能被修改,value能被修改的原理也很简单,就是在实例化的时候,声明第二个模板参数——在map中也就是pair,pair的first是const类型

	private:hash_bucket::HashTable<K, pair<const K, V>, KeyOfT, Hash> _ht;

问题五

unordered_map与unordered_set与map和set的红黑树封装相同,insert的返回值都是一个键值对
在这里插入图片描述

first是一个迭代器,second是一个bool类型

基于此性质,引出了map的计数功能,可以通过insert返回的迭代器查看是否有key值,如果不存在则插入,将value值赋值为1,如果key已经存在,则通过insert返回的迭代器将value++,以此实现计数功能,所以map实现了operator[],用来计数

	V& operator[](const K& key){return _ht.Insert(make_pair(key, V())).first->second;}

四、实现代码

MyUnorderedSet.h

#include "HashTable.h"namespace Tlzns
{template<class K, class Hash = HashFunc<K>>class unordered_set{public:struct KeyOfT{const K& operator()(const K& key){return  key;}};typedef typename hash_bucket::HashTable<K, K, KeyOfT, Hash>::const_iterator iterator;typedef typename hash_bucket::HashTable<K, K, KeyOfT, Hash>::const_iterator const_iterator;iterator begin()const{return _ht.begin();}iterator end()const{return _ht.end();}pair<iterator, bool> Insert(const K& key){auto ret = _ht.Insert(key);return pair<iterator, bool>(iterator(ret.first._node, ret.first._pht), ret.second);}bool Erase(const K& key){return _ht.Erase(key);}iterator Find(const K& key){return _ht.Find(key);}private:hash_bucket::HashTable<K, K, KeyOfT, Hash> _ht;};void test_set(){unordered_set<int> us;us.Insert(5);us.Insert(15);us.Insert(52);us.Insert(3);unordered_set<int>::iterator it = us.begin();while (it != us.end()){//*it += 5;cout << *it << " ";++it;}cout << endl;for (auto e : us){cout << e << " ";}cout << endl;}
}

MyUnorderedMap.h

#include "HashTable.h"namespace Tlzns
{template<class K, class V, class Hash = HashFunc<K>>class unordered_map{public:struct KeyOfT{const K& operator()(const pair<K, V>& kv){return  kv.first;}};typedef typename hash_bucket::HashTable<K, pair<const K, V>, KeyOfT, Hash>::iterator iterator;typedef typename hash_bucket::HashTable<K, pair<const K, V>, KeyOfT, Hash>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin()const{return _ht.begin();}const_iterator end()const{return _ht.end();}pair<iterator, bool> Insert(const pair<K, V>& kv){return _ht.Insert(kv);}bool Erase(const K& key){return _ht.Erase(key);}iterator Find(const K& key){return _ht.Find(key);}V& operator[](const K& key){return _ht.Insert(make_pair(key, V())).first->second;}private:hash_bucket::HashTable<K, pair<const K, V>, KeyOfT, Hash> _ht;};void test_map(){unordered_map<string, string> dict;dict.Insert(make_pair("sort", ""));dict.Insert(make_pair("string", ""));dict.Insert(make_pair("insert", ""));unordered_map<string, string>::const_iterator it = dict.begin();for (auto& kv : dict){//kv.first += 'x';kv.second += 'x';cout << kv.first << ":" << kv.second << endl;}cout << endl;string arr[] = { "香蕉", "甜瓜","苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };unordered_map<string, int> count_map;for (auto& e : arr){count_map[e]++;}for (auto& kv : count_map){cout << kv.first << ":" << kv.second << endl;}cout << endl;}
}

HashTable.h

#include <iostream>
#include <vector>using namespace std;template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};template<>
struct HashFunc<string>
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){hash *= 13;hash += e;}return hash;}
};namespace hash_bucket
{template<class T>struct HashNode{HashNode(const T& data):_data(data),_next(nullptr){}T _data;HashNode* _next;};template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>struct _HTIterator{typedef HashNode<T> Node;typedef _HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;_HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht):_node(node),_pht(pht){}_HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht):_node(node), _pht(pht){}_HTIterator(const iterator& x):_node(x._node), _pht(x._pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self operator++(){Hash hf;KeyOfT kot;size_t hashi = hf(kot(_node->_data)) % _pht->_t.size();if (_node->_next != nullptr){_node = _node->_next;}else{hashi++;while (hashi < _pht->_t.size()){if (_pht->_t[hashi]){_node = _pht->_t[hashi];break;}hashi++;}}if (hashi == _pht->_t.size()){_node = nullptr;}return *this;}bool operator==(const Self& it){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}const HashTable<K, T, KeyOfT, Hash>* _pht;Node* _node;};template<class K, class T, class KeyOfT, class Hash>class HashTable{typedef HashNode<T> Node;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct _HTIterator;public:HashTable(size_t n = 10){_t.resize(n);}typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;typedef _HTIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;iterator begin(){size_t hashi = 0;while (hashi < _t.size()){if (_t[hashi]){break;}hashi++;}if (hashi == _t.size()){return iterator(nullptr, this);}return iterator(_t[hashi], this);}iterator end(){return iterator(nullptr, this);}const_iterator begin()const{size_t hashi = 0;while (hashi < _t.size()){if (_t[hashi]){break;}hashi++;}if (hashi == _t.size()){return iterator(nullptr, this);}return iterator(_t[hashi], this);}const_iterator end()const{return iterator(nullptr, this);}pair<iterator,bool> Insert(const T& data){KeyOfT kot;Hash hf;iterator ret = Find(kot(data));if (ret != end()){return make_pair(ret, false);}//扩容if (_n / _t.size() == 1){size_t newsize = _t.size() * 2;HashTable newtable(newsize);for (int i = 0; i < _n; i++){Node* cur = _t[i];while (cur){Node* next = cur->_next;size_t hashi = hf(kot(cur->_data)) % newsize;cur->_next = newtable._t[hashi];newtable._t[hashi] = cur;cur = next;}_t[i] = nullptr;}swap(_t, newtable._t);}size_t  hashi = hf(kot(data)) % _t.size();Node* newnode = new Node(data);newnode->_next = _t[hashi];_t[hashi] = newnode;_n++;return make_pair(iterator(newnode, this), true);}iterator Find(const K& key){Hash hf;KeyOfT kot;size_t hashi = hf(key) % _t.size();Node* cur = _t[hashi];while (cur){if (kot(cur->_data) == key){return iterator(cur, this);}cur = cur->_next;}return iterator(nullptr, this);}bool Erase(const K& key){Hash hf;KeyOfT kot;size_t hashi = hf(key) % _t.size();Node* cur = _t[hashi];Node* prev = nullptr;if (kot(cur->_data) == key){_t[hashi] = cur->_next;delete cur;return true;}while (cur){if (kot(cur->_data) == key){prev->_next = cur->_next;delete cur;_n--;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<HashNode<T>*> _t;size_t _n = 0;};
}

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

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

相关文章

gcc CFI控制流完整性保护

一、CFI简介 GCC的CFI&#xff08;Control Flow Integrity&#xff0c;控制流完整性&#xff09;机制是一种用于防止针对函数指针和虚函数表的攻击的保护机制。它通过在编译时对程序进行加固&#xff0c;限制了程序中可能的跳转目标&#xff0c;以提高程序运行时的安全性。下面…

WebGL笔记:矩阵缩放的数学原理和实现

矩阵缩放的数学原理 和平移一样&#xff0c;以同样的原理&#xff0c;也可以理解缩放矩阵让向量OA基于原点进行缩放 x方向上缩放&#xff1a;sxy方向上缩放&#xff1a;syz方向上缩放&#xff1a;sz 最终得到向量OB 矩阵缩放的应用 比如我要让顶点在x轴向缩放2&#xff0c;y轴…

1.1、Autosar_CP软件集群设计与集成指南说明

目录 前言 1、介绍 1.1、目标 1.2、范围 2、缩略语 3、相关文档

SpringBoot整合Druid数据库连接池

1. 引入依赖 <!-- 阿里数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.16</version></dependency><!-- Mysql驱动包 --><depen…

python爬虫AES魔改案例:某音乐素材下载网

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、找出需要加密的参数 js运行 atob(‘aHR0cHM6Ly93d3cuYWlnZWkuY29tL3NvdW5kL2NsYXNzLw’) 拿到网址&#xff0c;F12打开调…

html动漫网页设计分享 紫罗兰永恒花园网页作业成品带视频,注册登录,表格,表单

html5静态网页设计要是用HTML DIVCSS JS等来完成页面的排版设计,一般的网页作业需要融入以下知识点&#xff1a;div布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点&#xff0c;学生网页作业源码可以…

数据挖掘实战-基于word2vec的短文本情感分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

鸿蒙基础入门与高频知识点梳理

介绍鸿蒙高频知识点&#xff0c;持续更新中 一、鸿蒙代码结构 ├──entry/src/main/ets // 代码区 │ ├──common │ │ └──Constant.ets // 常量类 │ ├──entryability │ │ └──EntryAbility.ts // 程序入口类 │ ├──p…

solidity案例详解(五)能源电力竞拍合约

使用智能合约对电力公司和用户拍拍进行一个管理与上链&#xff0c;确保安全性&#xff0c;合约完整代码私信或加裙851453227 a)现有系统架构和功能&#xff0c;服务提供方是谁&#xff0c;用户是谁&#xff1b; 系统架构&#xff1a; 电力拍卖系统&#xff0c;由能源公司部署。…

【算法】单调队列 滑动窗口最大值

文章目录 例题——239. 滑动窗口最大值相关练习1438. 绝对差不超过限制的最长连续子数组解法1——两个单调队列分别维护最大值和最小值解法2——有序集合TreeMap 2398. 预算内的最多机器人数目解法1——二分答案 单调队列解法2——双指针 单调队列 &#xff08;不固定大小的滑…

并发编程1:线程的基本概念

一、进程、线程、用户线程&原生线程、优先级、守护线程 什么是进程 是程序一次执行的过程&#xff0c;是系统运行程序的基本单位。系统运行一次程序&#xff0c;就是一个进程从创建到关闭的过程。Java 项目从 main 方法启动&#xff0c;就是启动了一个 JVM 进程&#xff…

JS中闭包

相信JS的开发者&#xff0c;对闭包这个知识都比较熟悉&#xff0c;在熟悉的同时可能会有些模糊的不真切感&#xff0c;下面咱们从三个方面来具体加深一下对闭包的理解。 什么是闭包 咱们先看两个比较抽象的理解&#xff0c;闭包是一个函数和其关联环境组成的结构体&#xff1b…

C++面试宝典第1题:爬楼梯

题目 小乐爬楼梯&#xff0c;一次只能上1级或者2级台阶。楼梯一共有n级台阶&#xff0c;请问总共有多少种方法可以爬上楼&#xff1f; 解析 这道题虽然是一道编程题&#xff0c;但实际上更是一道数学题&#xff0c;着重考察应聘者的逻辑思维能力和分析解决问题的能力。 当楼梯只…

理解Zookeper

一、什么是Zookeper Zookeper是一个可以作为注册中心、配置中心、分布式锁的分布式解决方案 二、数据一致性 一致性分为强一致性、弱一致性、最终一致性 Zookeper可以保持数据的强一致性&#xff08;CP&#xff09; 主要是解决写、集群节点的同步、读之间的关系 强一致性&a…

nodejs微信小程序+python+PHP问卷调查系统的设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

This详细用法

this的指向 this有5种指向&#xff0c;在普通函数中&#xff0c;this指向window&#xff1b;在构造函数中&#xff0c;this指向创建的对象&#xff1b;在方法声明中&#xff0c;this指向调用者&#xff1b;在定时器中&#xff0c; this指向window&#xff1b;在事件中&#xff…

超大规模集成电路设计----MOS器件原理(二)

本文仅供学习&#xff0c;不作任何商业用途&#xff0c;严禁转载。绝大部分资料来自----数字集成电路——电路、系统与设计(第二版)及中国科学院段成华教授PPT 超大规模集成电路设计----MOS器件原理&#xff08;二&#xff09; 半导体物理知识补充介绍1. 半导体材料2. 固体类型…

如何做性能优化?

性能优化是一个复杂的过程&#xff0c;它涉及到对软件或网站的结构、代码、数据库和硬件的深入理解和改进。以下是一些通用的性能优化建议&#xff1a; 代码优化&#xff1a; 减少数据库查询&#xff1a;尽量避免N1查询问题&#xff0c;使用索引优化&#xff0c;或者考虑使用内…

如何查看JDK动态代理自动生成的类

JDK提供了一种强大且灵活的机制,可以在运行时生成代理类。这种动态生成的代理类可以在不修改原始类的情况下,对其方法进行拦截和增强。然而,对于初学者来说,了解生成的代理类的内部结构和工作原理可能会很有帮助。 本文将介绍如何查看JDK动态代理生成的代理类。我们将探索一…

RK3568平台开发系列讲解(Linux系统篇)通过OF函数获取属性

🚀返回专栏总目录 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍通过OF函数获取属性。 一、获取获取属性 ① of_find_property 函数 of_find_property 函数用于在设备树中查找节点 下具有指定名称的属性。 如果找到了该属性, 可以通过返回的属性结构体…