闭包,看这一篇就够了——带你看透闭包的本质,百发百中

1、概念 闭包函数:声明在一个函数中的函数,叫做闭包函数。 闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。 2、特点 让外部访问函数内部变量成为可能; 局部变量会常驻在内存中; 可以避免使用全局变量,防止全局变量污染; 会造成内存泄漏(有一块内存空间被长期占用,而不被释放) 3、闭包的创建:­­­ 闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,互不干扰。闭包会发生内存泄漏,每次外部函数执行的时 候,外部函数的引用地址不同,都会重新创建一个新的地址。但凡是当前活动对象中有被内部子集引用的数据,那么这个时候,这个数据不删除,保留一根指针给内部活动对象。 闭包内存泄漏为: key = value,key 被删除了 value 常驻内存中; 局部变量闭包升级版(中间引用的变量) => 自由变量; 上面的都是什么鬼,是人话么,能看懂早就看懂了,生气······ 不过,答应我,看完例子再回看上面的概念,会理解的更!透!彻! ---------------------------------------------我是容易看懂的分界线----------------------------------------------- 4、闭包的应用场景 结论:闭包找到的是同一地址中父级函数中对应变量最终的值 最终秘诀就这一句话,每个例子请自行带入这个结论!!!!!!!!!!!!! /* 例子1 */ function funA(){ var a = 10; // funA的活动对象之中; return function(){ //匿名函数的活动对象; alert(a); } } var b = funA(); b(); //10 /* 例子2 */ function outerFn(){ var i = 0; function innerFn(){ i++; console.log(i); } return innerFn; } var inner = outerFn(); //每次外部函数执行的时候,都会开辟一块内存空间,外部函数的地址不同,都会重新创建一个新的地址 inner(); inner(); inner(); var inner2 = outerFn(); inner2(); inner2(); inner2(); //1 2 3 1 2 3 /* 例子3 */

xtrabackup备份原理解析

对于数据量大的数据库来说,xtrabackup是作为mysql最好的热备份工具。 xtrabackup内容解析: 首先做一次全量备份: xtrabackup -uroot -p123456 --backup -S /usr/local/mysql/mysql.sock 第一部分(对于innodb表的备份): 190422 16:14:28 version_check Connected to MySQL server 190422 16:14:28 version_check Executing a version check against the server... 190422 16:14:28 version_check Done. 190422 16:14:28 Connecting to MySQL server host: localhost, user: root, password: set, port: not set, socket: /usr/local/mysql/mysql.sock Using server version 5.7.23-log xtrabackup version 2.4.12 based on MySQL server 5.7.19 Linux (x86_64) (revision id: 170eb8c) xtrabackup: uses posix_fadvise(). xtrabackup: cd to /usr/local/mysql/data

带宽规划

文章目录 带宽规划参考 带宽规划 在表示带宽大小的时候通常表示为1Gb/s 和10 Gb/s 。我们可以称为千兆位网络和万兆位网络。1Gb/s表示每秒可以传输 1G个字节,1G字节换算成我们存储的单位是128MB,在存储的时候我们表示的是字节,而传输的时候表示的是bit位,一个字节包含8个bit位。假设我们有一个实时处理系统没秒需要处理1TB的数据,每台设备的带宽是1Gb,我们需要多少台设备并行处理呢? 假设每小时处理1TB,那么每秒需要处理292MB,292MB换算成bit是2336Mb,那么假设在理想的情况下,不考虑流量高峰且带宽资源充分利用,那么需要2336Mb/1024Mb=2.2台设备来并行处理。当然实际上需要考虑带宽的利用率,以及流量峰值,如果说假设带宽利用率是70%,平均流量我们设定为带宽上限的1/3,避免突发流量,那么需要的设备台数就是2.2*3/0.7 = 10台(向上取整)。 参考 https://juejin.im/post/5bd464ccf265da0ac3735124

ajax在后端获取不到请求参数,但是前端已经传递过去了

使用ajax如果使用的是post方式提交数据,如果不设置content-type为application/x-www-form-urlencoded的话,默认的模式text/plain;charset=utf-8。 在tomcat中对于post提交方式又做了特殊的处理如果提交方式为post而content-type又不等于application/x-www-form-urlencoded,在tomcat底层是不会去解析请求参数的,也不会放到requestparameter的map中,因此使用request.getParameter(name)也就获取不到请求的参数了。 在浏览器中network中,一般post提交方式提交的数据也是会显示在form date下,而不是request payload下。

用C语言打开文件的几种方式及区别

文件使用方式含义如果指定的文件不存在r(只读)读取一个已经存在的文本文件出错w(只写)打开一个文本文件,输出数据,若文件存在则文件长度清为0,即该文件内容会消失建立新文件a (追加)向文本文件末尾添加数据,原来文件中的数据保留,新的数据添加到文件为,原文件EOF保留建立新文件rb(只读)读取一个二进制文件出错wb(只写)打开一个二进制文件,输出数据,若文件存在则文件长度清为0,即该文件内容会消失建立新文件ab (追加)向二进制文件尾添加数据建立新文件r+ (读写)对一个文本文件进行读写操作出错w+ (读写)对一个文本文件进行读写操作,若文件存在则文件长度清为0,即该文件内容会消失建立新文件a+(读写)向文本文件末尾添加数据,原来文件中的数据保留,新的数据添加到文件尾,原文件EOF不保留建立新文件rb+ (读写)读写一个二进制文件出错wb+ (读写)对一个二进制文件进行读写操作,若文件存在则文件长度清为0,即该文件内容会消失建立新文件ab+(读写)向二进制文件末尾添加数据,原来文件中的数据保留,新的数据添加到文件尾建立新文件 r+具有读写属性,从文件头开始写,保留原文件中没有被覆盖的内容; w+也具有读写属性,写的时候如果文件存在,会被清空,从头开始写。 先读后写先写后读的问题 再用C语言对文件先读后写或者先写后读时,一定要注意文件指针的位置情况。不然可能导致本该重写的以追加方式写入等错误。 e.g. The output of the follwing code is supposed to be: (and it is with gcc on linux) num:10 ret:1 num:30 ret:1 ==========++ 10 ## 30 40 But instead it completely ignores the overwrite and only moves the file pointer and the output comes out as: num:10 ret:1 num:30 ret:1 ============ 10 20 30 40 however if the two lines for the first fscanf and printf are commented, the output becomes: num:20 ret:1 ============ ## 20 30 40 Why?

解决 React-Native mac10.14.4 运行报错 error Failed to build iOS project

React-Native 开发的项目,Android 方面没有任何问题,IOS 就是无法跑起来,报错信息如下: mac 10.14.4 xcode 10.2.1 error Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65. To debug build logs further, consider building your app with Xcode.app, by opening reactNative.xcodeproj 复制代码 解决方法 删除项目依赖包以及 yarn 缓存 rm -rf node_modules && yarn cache clean 复制代码 重新装包 yarn install 复制代码 清除 React-Native 缓存 rm -rf ~/.rncache 复制代码 下载 React-Native IOS 运行依赖 直接运行下载脚本,若直接下载完成,后面的步骤就不用看了,直接运行项目 react-native run-ios 即可

CSS - 使表格td中的文字垂直居中

文字垂直居中的有如下的方法 方法一: valign:middle // 不推荐使用 代码如下: <table> <tbody> <tr> <td valign="middle" >垂直居中</td> </tr> </tbody> </table> 方法二: style="display:table-cell; vertical-align:middle" 代码如下: <table> <tbody> <tr> <td style="display:table-cell; vertical-align:middle">垂直居中</td> </tr> </tbody> </table> 方法三: style="height:20px; /*高度根据实际情况设置*/ line-height :22px; /*根据实际情况设置到达垂直居中即可*/" 代码如下: <table> <tbody> <tr> <td style="height:20px;line-height:22px;">垂直居中</td> </tr> </tbody> </table> 参考 https://zhidao.baidu.com/question/584912262.html 后续补充 ...

div或img图片高度随宽度自适应

1.应用场景 主要用来做网站自适应的,同时可以实现撑起内容高度,避免图片加载后导致的页面滚动。 2.学习/操作 1.实现思路 方式一: 使用js判断图片的宽度得到具体数值之后,再来利用js设置图片的高度[不再细说],利用js来实现有一个缺点是只能在页面刷新的时候才能调整图片的高度,不能随着浏览器的窗口大小变化来实现自适应。 方式二: 使用css来实现图片高度的自适应 这里使用方式二,code如下: <div class="box"> <span>行内元素垂直居中</span> <div class="img-box"> <img src="123.jpg"/> </div> </div> .box{ width: 50%; margin: 50px auto; } .img-box{ width: 100%; position:relative; z-index:1; } .img-box img{ position:absolute; top:0; bottom:0; left:0; right:0; width:100%; margin:auto; z-index: -1; *zoom:1; } .img-box:before { content: ""; display: inline-block; padding-bottom: 100%; width: 0.1px; /*必须要有数值,否则无法把高度撑起来*/ vertical-align: middle; } 3.问题 TBD 4.参考 https://blog.csdn.net/zh_rey/article/details/69666232 后续补充...

OpenDroneMap

OpenDroneMap 该项目OpenDroneMap 是一个开源的航拍图像处理工具,可以把航拍图像进行点云、正射影像和高程模型等转换处理。大疆最近也出了自己的处理工具,据我所知的,还有PhotoScan,Pix4d等,都有相似的功能。 安装测试 这里采用了测试安装了WEB版本的,安装很简单,下载以后照着官方文档敲命令就可以了。注意端口是8000哦。 奈何服务器不给力,才扔了17张航拍图就要跑好久。 更新: 航拍图是6000*4000的,我又重新下采样到512*341传上去5张图跑出来了结果。下面是一些长长的厂房。哈哈,突然有点吃鸡地图的感觉。更多图像正在测试,有需要的可以留言,帮你开个可以用的账号。

WEB服务器-TCP协议之三次握手与四次挥手

本文经过借鉴书籍资料【图解HTTP】、他人博客总结出的知识点。如有冒犯,欢迎联系。 三次握手 与 四次挥手 三次握手:建立连接,保证双方准备资源 四次挥手:断开连接,将资源释放掉 所谓三次握手(Three-Way Handshake)即建立TCP连接,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。 所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。 HTTP与TCP 的区别 HTTP是应用层协议,TCP是传输层协议! 从本质上来说,二者没有可比性。Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。而在这个过程中,也就是数据包在网络传输过程中,HTTP被封装在TCP包内!客户端发送的每一次请求,都需要服务端的返回响应。客户端在收到服务端的响应后,主动关闭连接通道。至此,一次TCP连接过程完成。 TCP协议 TCP协议属于传输层协议(UDP也属于传输层协议,但是UDP协议是无状态的)。建立一个TCP连接需要三次握手,断开一个TCP连接需要四次挥手。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。 TCP报文格式 TCP报文格式图 上图中有几个字段需要重点介绍下: 序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。 确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。 标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下: URG:紧急指针(urgent pointer)有效。 ACK:确认序号有效。 PSH:接收方应该尽快将这个报文交给应用层。 RST:重置连接。 SYN:发起一个新连接。 FIN:释放一个连接 TCP三次握手连接和四次挥手断开过程详解 TCP 建立连接需要三次握手 三次握手过程理解 建立连接的过程,主要步骤如下: 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。 TCP 断开连接需要四次挥手 四次挥手过程理解 断开连接的过程,主要步骤如下: 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。 关于四次挥手 先由客户端向服务器端发送一个FIN,请求关闭数据传输。 当服务器接收到客户端的FIN时,向客户端发送一个ACK,其中ack的值等于FIN+SEQ 然后服务器向客户端发送一个FIN,告诉客户端应用程序关闭。 当客户端收到服务器端的FIN是,回复一个ACK给服务器端。其中ack的值等于FIN+SEQ 为什么要四次挥手? 确保数据能够完整传输。 当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。 但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后, 再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。 典型面试题 关于三次握手与四次挥手通常都会有典型的面试题,在此提出供有需求的兄弟姐妹们参考: 1、三次握手是什么或者流程?四次握手呢? 答案前面分析就是。 2、为什么建立连接是三次握手,而关闭连接却是四次挥手呢? 这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了, 所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接. 因此,己方ACK和FIN一般都会分开发送。 3、为什么不能用两次握手进行连接? 3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好), 也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。 现在把三次握手改成仅需要两次握手,死锁是可能发生的。 作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组, S收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了, 可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好, 不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下, C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。 而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。 4、如果已经建立了连接,但是客户端突然出现故障了怎么办?

代理模式---论坛权限控制代理

论坛权限控制代理 在一个论坛中已注册用户和游客的权限不同,已注册的用户拥有看帖、发帖、修改自己的帖子等功能;而游客只能看帖,没有其他权限。使用代理模式来设计该权限管理模块。 在本实例中我们使用代理模式中的保护代理,该代理用于控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。 BBS.java package bbsProxy; public interface BBS { public void function(); } RealBBS.java package bbsProxy; public class RealBBS implements BBS { @Override public void function() { // TODO Auto-generated method stub System.err.println("您可以有以下权限:"); System.err.println("看帖、发帖、修改自己的帖子"); } } Proxy.java package bbsProxy; public class Proxy implements BBS { private RealBBS bbs=new RealBBS();//维持一个对对真实主题对象的引用 private int permission=2; //权限 private String name; public Proxy(String name,int permission) { this.name=name; this.permission=permission; } @Override public void function() { // TODO Auto-generated method stub if(permission>=2) { System.

c语言逆向输出链表中的值

这道题其实挺简单的,不过为了拓宽思路,这里我来记录三个方法 ?1 通过将其按照头插法插入另一个链表中,然后顺序输出新链表值就行。这个也是我们的常规思路啦 //先倒序存到一个新的链表中,然后输出 //采用头插法即可 void reverse_output(Node* head) { Node* reverse_first = (Node*)malloc(sizeof(Node)); assert(reverse_first); reverse_first -> data = 0; reverse_first -> next = NULL; Node* p = head->next; while(p) { Node* save = p; p = p->next; save->next = reverse_first->next; reverse_first->next = save; } print_list(reverse_first); } ?2 由于是逆序,所以我们就很自然的想到用栈来实现啦,这里我借助的是顺序栈 //从尾到头,反向输出每个节点的值 //借助栈来实现 #include<stdio.h> #include<stdlib.h> #include<assert.h> #define true 1 #define false 0 #define STACK_MAXSIZE 100 #define STACK_INCREMENT 10 typedef struct Node { int data; struct Node* next; }Node; //用顺序存储栈 typedef struct Stack { int* base; int* top; int stacksize; }Sqstack; void InitStack(Sqstack* S) { S->base = (int* )malloc(STACK_MAXSIZE * sizeof(int)); if(!

终极解决方案UnicodeEncodeError: 'ascii' codec can't encode character u'\uff08' in position 13: ordinal not

又遇到报错: UnicodeEncodeError: 'ascii' codec can't encode character u'\uff08' in position 13: ordinal not in range(128) 这个问题遇到多次了了,但都是通过第一个方案解决了,但这次貌似不行了。最终采用了方案三,顺便整理下网上其他方案 第一种方案(90%情况下,大部分帖子都是这个) 一般报错到代码都是自己写到代码,代码上添加 import sys reload(sys) sys.setdefaultencoding('utf-8') 第二种方案,引用到包出现错误(未解决我的问题,但有人提到过这种处理方案) 在python的lib\site-packages文件夹下新建一个sitecustomize.py cat sitecustomize.py #添加如下内容,设置编码为utf8 #encoding=utf8 import sys reload(sys) sys.setdefaultencoding('utf8') 参考:https://www.cnblogs.com/kevingrace/p/5893121.html 第三种方案 进入python终端,执行如下命令 import sys, codecs, locale; print str(sys.stdout.encoding); 是否时utf8(ubunut系统) 如果不是,比如我的是这个 'ANSI_X3.4-1968' 则修改环境变量PYTHONIOENCODING为utf8 执行:export PYTHONIOENCODING=utf-8

tensorflow之focal loss 实现

何凯明大佬的Focal Loss对交叉熵进行改进,主要解决分类问题中类别不均衡导致的模型训偏问题。 在计算机视觉(CV)任务里常常会碰到类别不平衡的问题, 例如: 1. 图片分类任务,有的类别图片多,有的类别图片少 2. 检测任务。现在的检测方法如SSD和RCNN系列,都使用anchor机制。 训练时正负anchor的比例很悬殊. 3. 分割任务, 背景像素数量通常远大于前景像素。 从实质上来讲, 它们可以归类成分类问题中的类别不平衡问题:对图片/anchor/像素的分类。 1. 交叉熵 2. focal loss 对于二分类,alpha取值0.25, gamma取值2效果比较好,可以根据自身任务调整参数: tensorflow实现

JAVA基础知识面向对象之 ---- 参数类型与返回值类型、修饰符

JAVA基础知识面向对象之 ---- 参数类型与返回值类型、修饰符 参数类型 A:基本数据类型作为形参: ​ 当一个方法的形参为基本数据类型时,就传对应的基本数据类型。 B:类名作为形参: ​ 当一个方法的形参要一个类 类型,就传一个该类的对象。 public class MyTest { public static void main(String[] args) { Student student = new Student(); int num=2; set(student,num); //调用set方法时就传一个该类的对象 student.show(new Student(),100); ///调用show方法时就传一个该类的对象 System.out.println(student.num); //100 } //set方法的形参要一个类 类型 public static void set(Student student,int num){ student.num=num; } } class Student{ int num=10; //show方法的形参要一个类 类型 public void show(Student student,int num){ student.num=num; } } C:抽象类名作为形参: ​ 当一个方法的形参要一个抽象类 类型,就传一个该抽象类的子类对象。 public class MyTest { public static void main(String[] args) { int num=1; Zi zi = new Zi(); set(new Zi(),num); //调用set方法,就传一个该抽象类的子类对象 zi.

c#制作ActiveX控件

使用VS2010制作ActiveX控件 工具/原料 一台windows操作平台的电脑VS2010工具 方法/步骤 新建一个项目,选window->类库(这里选控件库也是可以的) 在应用程序->程序集信息,勾选里面的“使程序集com可见” 然后在生成->勾选“为com互操作注册”然后重新生成解决方案 在AssemblyInfo.cs类里面添加一下内容 然后添加接口IObjectSafety.cs,这里的名字不要改它 接口里面的内容如下,特别注意的是这里面的guid 不能更改,只要将下面的代码复制到接口里面去就可以了 [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] interface IObjectSafety { [PreserveSig] int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions); [PreserveSig()] int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions); } 添加用户控件,然后在里面拉一个label控件,textbox控件,button控件,然后给button1添加一个点击事件 private void button1_Click(object sender, EventArgs e) { label1.Text = textBox1.Text; } 这里是生成guid,工具->创建guid,点击右边的复制就可以了 将刚才生成的guid添加到用户控件上面去,并且让用户控件继承接口IObjectSafety,并且在用户控件里面实现接口IObjectSafety,将下面的复制粘贴就可以了 #region IObjectSafety 成员 private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"; private const string _IID_IDispatchEx = "

java Lambda表达式示例

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。 Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。 使用 Lambda 表达式可以使代码变的更加简洁紧凑。 一、利用流和Lambda表达式对List集合进行处理 1.List集合遍历 // item:可以是任意值。类似于for循环中的循环值 dataList.forEach(item -> { //设置值 item.setName(item.getName()+"测试");; //输出语句 System.out.println(item.toString()); }); } 2.统计List集合 sum(),max(),min(),average() 。 mapToInt() 转换成int。还有其他类型转换。如:double。 int rowCount = list.stream().mapToInt(Paper::getRow).sum(); 3.对List集合分组 Collectors.groupingBy(属性名) Map<Integer, List<Product>> map = list.stream().collect(Collectors.groupingBy(Product::getType)); 4.多重分组 Collectors.groupingBy(属性,Collectors.groupingBy(属性)) Map<String, Map<Integer, List<Product>>> map2 = list.stream().collect(Collectors.groupingBy(t->t.getName(),Collectors.groupingBy(t->t.getType()))); 5.map(), 提取对象中的某一元素. 用每一项来获得属性(也可以直接用 对象::get属性()) List<String> mapList1 = list.stream().map(Product::getName).collect(Collectors.toList()); List<String> mapList2 = list.stream().map(item->item.getName()).collect(Collectors.toList()); 6.过滤 filter(item->{}) item为每一项。 按照自己的需求来筛选list中的数据 List<Person> filterList = list.stream().filter(item->item.getPrice()>100).collect(Collectors.toList()); 7. 去重 distinct() 去重;collect(Collectors.

java分词工具

一.导包 <dependency> <groupId>com.janeluo</groupId> <artifactId>ikanalyzer</artifactId> <version>2012_u6</version> </dependency> 二.用法 /** * 分词工具类 */ public class IKSUtil { public static List<String> getStringList(String text) throws Exception{ //独立Lucene实现 StringReader re = new StringReader(text); IKSegmenter ik = new IKSegmenter(re, true); Lexeme lex; List<String> s = new ArrayList<>(); while ((lex = ik.next()) != null) { s.add(lex.getLexemeText()); } return s; } } 三.结果 public static void main(String[] args) { try { List<String> stringList = getStringList("我是中国人"); System.out.println(stringList); } catch (Exception e) { e.

ffmpeg ./configure参数说明

Standard options: 基本选项参数 --help 显示此帮助信息|print this message --log[=FILE|yes|no] 记录测试并输出到config.err文件|log tests and output to FILE [config.err] --prefix=PREFIX 安装程序到指定目录(默认/usr/local)|install in PREFIX [/usr/local] --libdir=DIR 安装库到指定目录(默认prefix/lib)|install libs in DIR [PREFIX/lib] --shlibdir=DIR 指定共享库路径(默认prefix/lib)|install shared libs in DIR [PREFIX/lib] --incdir=DIR 指定includes路径(默认prefix/include/ffmpeg)|install includes in DIR[PREFIX/include/ffmpeg] --mandir=DIR 指定man page路径(默认prefix/man)install man page in DIR [PREFIX/man] --enable-mp3lame 启用mp3编码libmp3lame(默认关闭)enable MP3 encoding via libmp3lame[default=no] --enable-libogg 启用ogg支持libogg(默认关闭)enable Ogg support via libogg [default=no] --enable-vorbis 启用Vorbis支持libvorbis(默认关闭)enable Vorbis support via libvorbis [default=no] --enable-faad 启用faad支持libfaad(默认关闭)enable FAAD support via libfaad [default=no]

Mac 解决 PostgreSQL 链接问题

mac异常关机后总是无法使用postgresql数据库,解决办法: 删除postmaster.pid文件,然后重新启动postgresql。 启动 PostgreSQL: pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start 关闭 PostgreSQL: pg_ctl -D /usr/local/var/postgres stop -s -m fast 在 mac 下,可以利用 homebrew 直接安装 PostgreSQL: brew install postgresql -v 稍等片刻,PostgreSQL 就安装完成。接下来就是初始数据库,在终端执行一下命令,初始配置 PostgreSQL: initdb /usr/local/var/postgres -E utf8 上面指定 "/usr/local/var/postgres" 为 PostgreSQL 的配置数据存放目录,并且设置数据库数据编码是 utf8,更多配置信息可以 "initdb --help" 查看。 设成开机启动 PostgreSQL: ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist

Vmware 中Windows和虚拟机共享文件--VMware-tools补丁安装

结合之前搜到的一些讯息,大概可以判断出VMware Tools在Ubuntu下不稳定,一些功能会时不时自动失效,通过这个补丁来安装VMware Tools的话就能解决这些问题 现在就用这个补丁来安装VMware Tools吧! sudo apt-get install dkms linux-headers-$(uname -r) build-essential psmisc git clone https://github.com/rasa/vmware-tools-patches.git cd vmware-tools-patches Bash 然后对着虚拟机的标签页右键,选择“安装/重新安装VMware Tools” 。这时VMware会自动挂载CD驱动器,打开CD驱动器,找到 VMwareTools-x.x.x-xxxxxxx.tar.gz 文件 (x表示任意数字) 把它复制到vmware-tools-patches目录 ./untar-and-patch-and-compile.sh 然后它就会全自动帮你安装VMware Tools了 装完后重启,问题迎刃而解~

android 9.0上,实现双mipi屏

我们知道,在android上,本就支持mipi(primary display)、HDMI(external display)、wifi display、virtual display这四种屏,但是并不支持双mipi屏。如果需要做到集成双mipi屏,外面普通的作法有两个: 1.)在一套主板上用两个cpu、两套android代码,然后中间用一条USB数据线连接起来,实现两个display之间的数据交互。 2.)使用一个桥接芯片。 第1个方法,不仅在软硬件上相当的繁锁,而且成本极高,显然不合算。第2个方法,这个需要看主板上是否有这个桥接转换芯片,如果没有的话,也就没办法了。 目前我接手的这个项目上面,客户就要求在一个不带桥接芯片的主板上面,集成两个mipi屏,用来做同显和异显。针对这个要求和客观情况,我仔细分析后发现,其实这个需求并不难实现。 首先,我们android是运行在linux内核上的,无论我们用的是什么lcd,最终对应到linux内核上,无非就是fb0、fb1这样的设备节点而已。 明白了这一点后,我们就会发现,其实我们可以利用android系统本身就有的hdmi屏的接口来稍作修改,让fb0对应到主屏,fb1对应到副屏,也就是第二块mipi屏即可。 下面来说说具体的代码实现,我这个项目是基于高通平台8953芯片来做的来做的,高通的驱动代码在dtsi文件里来配置。对应的,我们的dtsi文件为msm8953-mdss.dtsi。在这个文件里,对lcd的驱动进行了配置。比如: mdss_fb0: qcom,mdss_fb_primary { cell-index = <0>; compatible = "qcom,mdss-fb"; qcom,cont-splash-memory { linux,contiguous-region = <&cont_splash_mem>; }; }; mdss_fb2: qcom,mdss_fb_wfd { cell-index = <2>; compatible = "qcom,mdss-fb"; }; mdss_fb1: qcom,mdss_fb_secondary { cell-index = <1>; compatible = "qcom,mdss-fb"; }; }; qcom,mdss-fb-map-prim = <&mdss_fb0>; qcom,mdss-fb-map-sec = <&mdss_fb1>; mdss_dsi0: qcom,mdss_dsi_ctrl0@1a94000 { compatible = "qcom,mdss-dsi-ctrl"; label = "MDSS DSI CTRL->0"; qcom,display-id = "primary"; cell-index = <0>; reg = <0x1a94000 0x400>, <0x1a94400 0x580>, <0x193e000 0x30>; reg-names = "

freeswitch学习笔记:注册到运营商服务器、作为网关呼出、随机选线等操作

注册到运营商服务器 我们可以在FreeSWITCH中添加一些网关,以便注册到运营商的SIP服务器上去(应该是一个SBC)。 网关的配置文件如下,为了使用方便,我们让网关名称(name)的后两位与号码的最后两位相同: <gateway name="gw30"> <param name="realm" value="218.56.x.x"/> <param name="username" value="xxxxxx30"/> <param name="password" value="xxxx"/> <param name="register" value="true"/> </gateway> <gateway name="yt31"> <param name="realm" value="218.56.x.x"/> <param name="username" value="xxxxxx31"/> <param name="password" value="xxxx"/> <param name="register" value="true"/> </gateway> ...... 上面我们仅列出了两个网关账号的配置,其他账号依此类推。 通过单个号码呼出 配置的网关注册成功后,我们就可以通过这个号码(又称为线路)打入打出电话了。我们可以使用 如下命令快速试一下是否能通过某一条线路(如gw30)成功呼出: freeswitch> originate sofia/gateway/gw30/1860535xxxx &echo 测试成功后,就可以设置如下的Dialplan让所有分机都可以通过该网关呼出了: <extension name="Outbound Call"> <condition field="destination_number" expression="^(1[358].*)$"> <action application="bridge" data="sofia/gateway/gw30/$1"/> </condition> </extension> 使用随机数做号码连选 为了能自动选择一个网关呼出,我们想办法从这10个网关中自动选择一个进行呼出。这种选择的过程就称为 选线,也称为号码连选。当然,号码连选最简单的实现方法是使用一个随机数。见下面的Dialplan: <action application="set" data="gw=gw${expr(randomize(&x);ceil(random(30,39,&x)))"/> <action application="bridge" data="sofia/gateway/${gw}/$1"/> 其中,“expr”是一个API,我们用它的randomize方法产生一个从30到39之间的随机数(如33),在该随机 数前面加上“gw”字符(变为gw33),并把它赋值给一个“gw”通道变量(使用“set”)实现。有了该通道变量 后,在“bridge”的参数中就可以使用“${gw}”引用该变量(在本例中它的值就是gw33),实现动态选择一个随 机的网关。 当然,这种选线算法有一个缺点,就是它不记录实际号码的忙闲状态,如果选到正在通话的号码时,通话还 是会失败。通过下面的方式,我们可以做一个改进的算法:

消息ID的范围

在大型软件开发过程中,会发现自己创建的菜单状态为灰色,无法使用。 这是因为MFC主动产生的消息ID是根据之前使用情况累加的数字,长久使用的情况下会造成ID的数目非常大,且中间会产生很多的空隙。 MFC中规定消息ID最大为65535,大于65535则会发生溢出,造成创建的消息无法响应,界面上显示为灰色。 ,

HAL库教程9:串口接收不定长数据

串口收到的两组数据之间,往往会有一定的时间间隔。可以判断这个间隔,来实现无需结束符,无需指定长度,串口可接收不定长数据的功能。如果串口在一定的时间内没有收到新的数据,可以认为一组数据已经接收完毕了。思路是用定时器来设置一个“闹钟”,连续的一段时间没有收到新的数据,闹钟响起,就把已经收到的数据打包,做相应处理。 定时器溢出时间配置 首先修改定时器的溢出时间。本文规定使用5ms的间隔。在某些通信协议中,会规定间隔时间。例如Modbus规定两组数据之间要间隔3.5字符。 实际上,间隔的时间常常与通信的波特率是相关的。在9600波特率下,一个字节的数据共 起始+8数据+结束=10位,一位是104us,所以一个字节的数据是1.04ms,3.5个字节,我们就认为是4ms。有时可能有校验位,稍微保险一点,5ms吧。假如使用115200的波特率,5ms已经算是非常“奢侈”了。 本文使用定时器3来计时,配置的PSC为8399,ARR为49,可得5ms的溢出时间,配置过程可以参考通用定时器章节。 串口接收中断服务函数 我们在串口接收中断服务中,把收到的所有数据都放到数组中去,判断收到的是否是第一个字符,如果是则开启定时器。 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1) { __HAL_TIM_SET_COUNTER(&htim3,0); if(0 == UART1_Rx_cnt)//如果是第一个字符,则开启定时器 { __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE); HAL_TIM_Base_Start_IT(&htim3); } UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0]; UART1_Rx_cnt++; HAL_UART_Receive_IT(&huart1,(uint8_t *)UART1_temp,REC_LENGTH); } } 其中__HAL_TIM_SET_COUNTER是HAL提供的一个宏定义,类似于函数,功能是通过宏来直接修改寄存器的值。 由于HAL库的串口接收中断在每次执行后都会关闭,所有在串口的中断里要重新手动开启串口接收中断。 另外,由于定时器中断在开启定时器的时候就会执行,所以需要开启定时器之前就把中断标记位清除。 定时器中断服务 一旦定时器发生溢出中断,说明已经到了5ms的时间间隔,可以把数据截断,根据业务需求来做相应处理,我的做法是设着一个标志位,然后在主函数的死循环内不断检测标志位,如果标志位被置1,则把收到的数据发送出去。 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim==(&htim3)) { LED1 = !LED1; UART1_Rx_flg = 1; HAL_TIM_Base_Stop_IT(&htim3);//关闭定时器 } } //main() while(1) if(UART1_Rx_flg) { HAL_UART_Transmit(&huart1,UART1_Rx_Buf,UART1_Rx_cnt,0xffff); //发送接收到的数据 for(int i = 0;i<UART1_Rx_cnt;i++) UART1_Rx_Buf[i] = 0; UART1_Rx_cnt = 0; UART1_Rx_flg = 0; } 功能是串口接收什么就回复什么,但无需结束符,也不用指定长度。当然最长不能超过UART1_Rx_Buf数据的大小。

在 React Hooks 中如何请求数据?

通过这个教程,我想告诉你在 React 中如何使用 state 和 effect 这两种 hooks 去请求数据。我们将使用众所周知的 Hacker News API 来获取一些热门文章。你将定义属于你自己的数据请求的 Hooks ,并且可以在你所有的应用中复用,也可以发布到 npm 。 如果你不了解 React 的这些新特性,可以查看我的另一篇文章 introduction to React Hooks。如果你想直接查看文章的示例,可以直接 checkout 这个 Github 仓库。 注意:在 React 未来的版本中,Hooks 将不会用了获取数据,取而代之的是一种叫做 Suspense 的东西。尽管如此,下面的方法依然是了解 state 和 effect 两种 Hooks 的好方法。 使用 React Hooks 进行数据请求 如果你没有过在 React 中进行数据请求的经验,可以阅读我的文章:How to fetch data in React。文章讲解了如何使用 Class components 获取数据,如何使用可重用的 Render Props Components 和 Higher Order Components ,以及如何进行错误处理和 loading 状态。在本文中,我想用 Function components 和 React Hooks 来重现这一切。

leetcode hard 10. 正则表达式匹配

https://leetcode-cn.com/problems/regular-expression-matching/ 思路:动态规划 dp:(len(s) +1)* (len(p) + 1)dp[ii][jj]代表s[0,i-1]和p[0,j-1]是否匹配,故有ii=i+1,jj=j+1。也就是说i,j对应比较时候改变的是dp[i+1][j+1]时的位置。边界情况,s='',需要先把第一行初始化,这时候就是下面的特殊情况,即当p[j]=='*'时,s[i]!=p[j-1],dp[ii][jj] = dp[ii][jj-2]。先分两类: s[i]==p[j],(或p[j]=='.')dp[ii][jj] = dp[ii-1][jj-1],当前两个字符相等,只需要各退一步看是否相等。s[i]==p[j],p[j]=='*',再分两大类。为了简便,设置Sx,Pzy,y='*'。s[i]!=p[j-1],即x!=z,则Sx必须和P匹配,dp[ii][jj] = dp[ii][jj-2]s[i]==p[j-1],即x==z,分几种匹配情况。Sx和P匹配,x和z*匹配,dp[ii][jj] = dp[ii][jj-2]Sx和Pz匹配,''和*匹配,dp[ii][jj] = dp[ii][jj-1]S和P匹配,x和z*匹配,dp[ii][jj] = dp[ii-1][jj-2]S和Pz匹配,x和*匹配,dp[ii][jj] = dp[ii-1][jj-1]S和Pz*匹配,x和*匹配,dp[ii][jj] = dp[ii-1][jj] 代码 class Solution(object): def isMatch(self, s, p): """ :type s: str :type p: str :rtype: bool """ if len(s) == 0 and len(p) == 0: return True dp = [] for i in range(len(s) + 1): dp.append([0] * (len(p) + 1)) dp[0][0] = 1 for j in range(len(p)): ii, jj = 0, j + 1 if p[j] == '*': if j > 0: dp[ii][jj] = dp[ii][jj - 2] for i in range(len(s)): for j in range(len(p)): ii, jj = i + 1, j + 1 if s[i] == p[j] or p[j] == '.

android 开机优化(类和资源预加载优化)

转自:https://blog.csdn.net/xxm282828/article/details/49095839 Android启动过程中针对类和资源部分预加载耗时比较久,这个部分需要优化,主要涉及的文件: ./base/core/java/com/android/internal/os/ZygoteInit.java 主要采取三个措施: 1. 修改ZygoteInit.java 中预加载资源函数preload() , preloadClasses(); 与 preloadResources(); 并行加载。 2. 修改读取配置信息过程中GC频率。 3. 提升进程优先级 1、资源和类并行加载: static void preload() { // Thread preloadRsThread = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub //将该资源加载放在子线程中 。加载资源文件要比加载classes文件要快,因此这里不提升子线程优先级。 preloadResources(); } }) ; preloadRsThread.start() ; preloadClasses(); //wait preloadRes complete. try { preloadRsThread.join() ; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //暴露什么问题。 preloadOpenGL(); } 2、减少GC的频繁调度:

JPA简介及其使用详解

一、Spring data JPA简介 Spring data JPA是Spring在ORM框架,以及JPA规范的基础上,封装的一套JPA应用框架,并提供了一整套的数据访问层解决方案。 二、Spring data JPA的功能 Spring data JPA的功能非常的强大,这里我们先跳过环境搭建这一步,来一睹Spring data JPA的“芳容”。 Spring data JPA提供给用户使用的,主要有以下几个接口: Repository:仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别CrudRepository:继承Repository,实现了一组CRUD相关的方法PagingAndSortingRepository:继承CrudRepository,实现了一组分页排序相关的方法JpaRepository:继承PagingAndSortingRepository,实现一组JPA规范相关的方法JpaSpecificationExecutor:比较特殊,不属于Repository体系,实现一组JPA Criteria查询相关的方法。 三、Spring data JPA的接口 1、CrudRepository接口 该接口的定义如下,总共提供了11个方法,基本上可以满足简单的CRUD操作以及批量操作: @NoRepositoryBean public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { <S extends T> S save(S entity);//保存 <S extends T> Iterable<S> save(Iterable<S> entities);//批量保存 T findOne(ID id);//根据id查询一个对象 boolean exists(ID id);//判断对象是否存在 Iterable<T> findAll();//查询所有的对象 Iterable<T> findAll(Iterable<ID> ids);//根据id列表查询所有的对象 long count();//计算对象的总个数 void delete(ID id);//根据id删除 void delete(T entity);//删除对象 void delete(Iterable<? extends T> entities);//批量删除 void deleteAll();//删除所有 } 2、PagingAndSortingRepository接口 PagingAndSortingRepository接口继承了CrudRepository接口。

java 高频面试题 208 道

Java 基础 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。 JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。 具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。 2. == 和 equals 的区别是什么? == 解读 对于基本类型和引用类型 == 的作用效果是不同的,如下所示: 基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同; 代码示例: String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.

STM32之LED配置

希望每天都能有所收获鸭~ 最近准备开始学习stm32,当然51的学习也会一起进行,如开头所讲,希望每天都能有所收获吧!!!菜鸟思维,写的可能会有一点繁琐,但是我觉得学习是要一步一步来的,也希望自己可以把每一点都弄懂,嗯,就是这样 开始学习之前当然要先搭建好学习环境,关于软件的下载以及工程搭建,CSDN上有很多博主写的都很详细,下面给出两篇参考博客,也是我在学习过程中借鉴的博客(博主写的可以说超级详细了): https://blog.csdn.net/qq_34952376/article/details/81166033https://blog.csdn.net/ReCclay/article/details/86616210 stm32编程方式有两种:一种是直接操作寄存器,另一种是配置库函数, emmm,感觉大多数情况下还是库函数比较好用,配置寄存器的话要记的东西比较多,感觉我也记不住,哈哈。但是关于寄存器的知识我们还是要了解的,具体知识可以参照《STM32中文参考手册》来学习,下面我们来说说怎么实现LED的配置的。 开始写配置LED的函数之前,我们还是和学习51时一样,需要先看一下原理图,明确一下LED的电路结构: 从原理图上我们可以看到:单片机的各个引脚是通过一个573锁存器和LED相连的,这个573我们在51里也很常见,需要注意的就是只有在使能573的情况下才能实现端口数据的传输,也就是说我们需要把N-LE对应的引脚拉高。 接下来我们找一下红线框部分对应的引脚(emmm,这里和51就不太一样,可以看一下图) 上面分别是J1和J2两个排针,上面的引脚是一一对应的,从开发板上我们也可以看到,这两个排针的对应引脚是用跳线帽连接在一起的(感觉很方便呀) N-LE对应的是PD2,而D0到D7这八个LED分别对应PC8-PC15 那么LED的配置是配置什么呢? 引脚模式,也可以理解成一种初始化函数,具体步骤是:配置端口时钟(时钟使能),设置引脚号,设置引脚速率,配置端口模式,配置输出数据。 下面我们就按照步骤来一步一步完成LED的配置: 配置端口时钟 明确: STM32的GPIO外设是挂接在APB2总线上的,所以要完成使能我们就需要设置APB2外设时钟使能寄存器,这时候可以查阅手册看一下APB2外设时钟使能寄存器的相关知识: 图上红色线框部分是GPIO外设的相关时钟,而我们从原理图上可以得知,LED配置需要使能的时钟是:GPIOC(IO端口C)和GPIOD(IO端口D) 置1表示使能 下面我们用两种方法来实现一下时钟的使能,也顺便理解比较一下stm32编程的两种方法: 配置寄存器法: 在stm32f10x.h文件(库函数内)中我们可以找到外设时钟使能寄存器的相关定义: RCC的声明,使用RCC_TypeDef类型指针对RCC端口时钟地址进行强制类型转换,也就是说把RCC_BASE强制转换成一个结构体指针,然后通过宏定义,替换成用RCC表示的,这样我们在结构体中定义的各个变量也就相应的移植到了RCC内部的地址空间。 好了,明确了上面的那些内容,我们就可以进行相应时钟(GPIOD和GPIOC)的使能了,GPIOC和GPIOD分别对应位4和位5,所以我们下面要做的就是让APB2外设时钟使能寄存器的位4和位5置1,看代码: RCC->APB2ENR |= (1 << 4);//使能GPIOC时钟 RCC->APB2ENR |= (1 << 5);//使能GPIOD时钟 我们上面解释过了RCC是一个结构体指针,APB2ENG是这个结构体内部声明的一个变量,所以在调用时就需要用 “->” 这个符号,下面以使能GPIOC为例解释一下为什么可以实现位4置1: 先来看1 << 4:1用16进制表示出来是:00000001,左移四位变成了00010000;RCC->APB2ENR |= (1 << 4),APB2外设时钟使能寄存器的复位值是00000000,和00010000进行或运算,结果是:00010000,实现了位4置1,并且不改变其它位 注意:位是从0 开始表示的,所以位4实际上就是第5位 调用库函数法: STM32有着非常好用的库函数,功能很全也很多,其中就有初始化时钟的函数,在stm32f10x_rcc.h文件中可以找到相关定义,然后可以点击函数名按快捷键F12,直接定位到函数体,然后我们就可以明白各个变量的含义了: 第一个变量表示使能哪一个时钟,NewState表示使能(ENABLE)还是不使能(DISABLE) 看代码: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOD和GPIOC /*还可以分开写*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOC RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);//使能GPIOD 设置引脚相关: 引脚号,引脚速率,引脚模式,也就是初始化引脚配置,我们这里就直接用库函数配置的方法来做: STM32的IO模式(引脚模式)有8种:模拟输入、浮空输入、上拉输入、下拉输入、通用推挽输出、通用开漏输出、复用推挽输出、复用开漏输出,这8种模式比较重要,想要详细了解的话,可以参照下面的博客: https://blog.csdn.net/techexchangeischeap/article/details/72569999 此外输出模式还包括3种输出速率,emmm,可以想见我们的库函数里对于这一部分肯定也是用结构体封装的。 在stm32f10x_gpio.h文件里我们可以找到相关定义: 在stm32f10x_gpio.h文件里我们可以找到对应的端口引脚定义: ok,现在我们来写引脚模式配置的部分,以GPIOD(PD2)为例说明: 思想就是:先定义一个GPIO_InitTypeDef类型的结构体变量,然后为这个结构体的各个变量赋值,然后再调用初始化函数 GPIO_InitTypeDef GPIO_InitStructure;//定义一个结构体变量 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//设置引脚号 GPIO_InitStructure.

个人笔记-大佬主页

一、 1.AI及lintcode https://blog.csdn.net/v_JULY_v 收藏博客(程序员编程艺术第十一章:最长公共子序列(LCS)问题) 2.图像 https://www.cnblogs.com/zhanjxcom/category/638348.html 3.C++ https://blog.csdn.net/my_business 4.OpenCV https://blog.csdn.net/zhaocj 赵春江 5.OpenCV https://blog.csdn.net/poem_qianmo 浅墨 6.OpenCV https://www.cnblogs.com/ronny/category/366234.html ☆Ronny丶 7.OpenCV教程 http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/tutorials.html 二、lintcode 1. 二叉树总结及部分Lintcode题目分析 1 2. lintcode简书专题 3. LintCode字符串题总结 4. C/C++语言中的int等基本数据类型所能表示的最大值最小值 5. Segmentation fault(Core Dump) 6. 二叉查找树C++实现 转载于:https://www.cnblogs.com/Tang-tangt/p/10706449.html

VC+++ 操作word

最近完成了一个使用VC++ 操作word生成扫描报告的功能,在这里将过程记录下来,开发环境为visual studio 2008 导入接口 首先在创建的MFC项目中引入word相关组件 右键点击 项目 --> 添加 --> 新类,在弹出的对话框中选择Typelib中的MFC类。 然后在弹出的对话框中选择文件,从文件中导入MSWORD.OLB组件。 这个文件的路径一般在C:\Program Files (x86)\Microsoft Office\Office14 中,注意:最后一层可能不一定是Office14,这个看机器中安装的office 版本。 选择之后会要求我们决定导入那些接口,为了方便我们导入所有接口。 导入之后可以看到项目中省成本了很多代码文件,这些就是系统生成的操作Word的相关类。 这里编译可能会报错,error C2786: “BOOL (HDC,int,int,int,int)”: __uuidof 的操作数无效 解决方法: 修改对应头文件 #import "C:\\Program Files\\Microsoft Office\\Office14\\MSWORD.OLB" no_namespace 为: #import "C:\\Program Files\\Microsoft Office\\Office14\\MSWORD.OLB" no_namespace raw_interfaces_only \ rename("FindText","_FindText") \ rename("Rectangle","_Rectangle") \ rename("ExitWindows","_ExitWindows") 再次编译,错误消失 常见接口介绍 要了解一些常见的类,我们首先需要明白这些接口的层次结构: Application(WORD 为例,只列出一部分) Documents(所有的文档) Document(一个文档) ...... Templates(所有模板) Template(一个模板) ...... Windows(所有窗口) Window Selection View Selection(编辑对象) Font Style Range 这些组件其实是采用远程调用的方式调用word进程来完成相关操作。 Application:相当于一个word进程,每次操作之前都需要一个application对象,这个对象用于创建一个word进程。Documents:相当于word中打开的所有文档,如果用过word编辑多个文件,那么这个概念应该很好理解Templates:是一个模板对象,至于word模板,不了解的请自行百度Windows:word进程中的窗口Selection:编辑对象。也就是我们要写入word文档中的内容。一般包括文本、样式、图形等等对象。 回忆一下我们手动编写word的情景,其实使用这些接口是很简单的。我们在使用word编辑的时候首先会打开word程序,这里对应在代码里面就是创建一个Application对象。然后我们会用word程序打开一个文档或者新建一个文档。这里对应着创建Documents对象并从中引用一个Document对象表示一个具体的文档。当然这个Document对象可以是新建的也可以是打开一个现有的。接着就是进行相关操作了,比如插入图片、插入表格、编写段落文本等等了。这些都对应着创建类似于Font、Style、TypeText对象,然后将这些对象进行添加的操作了。

ATCommand拨号

at+ :modem命令的标头,有它才执行。如 执行 at 返回一个 ok 表示modem接通正常。 CGDCONT=1 :定义PDP(分组数据协议类型)上下文,用于规定分组数据协议类型的字符串参数。 如 : AT+CGDCONT=1,”PPP”,”cmwap” 点对点协议 wap 接入点。 :(接入点名称)一个字符串参数,作为逻辑名称用于选择GGSN或外部分组数据网络。 AT+CGDCONT=1,”IP”,”cmnet” TCP/IP协议 net 接入点。 AT +CGDCONT=1, “IP”, “internet”; TCP/IP协议 internet 接入点。 在进行PPP拨号上网前,我们必须使用下面命令来设置APN: 中国移动: AT+CGDCONT=1,"IP","cmnet" OK 中国联通有两个APN: uninet和3gnet, 如果给3G卡的话,可以设置APN为3gnet AT+CGDCONT=1,"IP","uninet" OK AT+CGDCONT? +CGDCONT:1,"IP","uninet","0.0.0.0",0,0 OK 或设置APN为3gnet: AT+CGDCONT=1,"IP","3gnet" OK AT+CGDCONT? +CGDCONT:1,"IP","3gnet","0.0.0.0",0,0 OK 发现有的时候,设置不成功,经过验证正确的方法是,模组刚上电,或者刚复位的时候,先发送AT+CFUN=1,然后再去设置APN AT+CFUN=1 OK AT+CGDCONT=0,"IP","ctnb" OK 同时电信早期的APN是ctnet,现在的APN是ctnb。 AT命令控制上网 1. AT+CGATT=1 (Attach or detach from GPRS service, GPRS 附着状态) 说的简单点,这一步就是让SGSN (服务GPRS节点,你可以把它理解成与基站紧密相连的一台设备,他可能记录你的移动终端的位置,状态等等很多很多信息)知道你的存在并且认为你拥有GPRS功能。由于GSM和GPRS用的都是相同的基站,所以通常你的MS开启,注册上网络了,你就已经是GSM的一个节点了,可以打电话了。但是,如果你想使用GPRS数据业务,你就要附着GPRS服务,这个命令就是干这个的。 2. AT+CGDCONT=1,"IP","CMNET" (Define PDP context, 定义PDP 上下文)

pid调节的方法

上一篇介绍了建立系统模型的三种方法,这一篇介绍如何调节pid,并用MATLAB仿真 调节pid的目标就是使得从模型中得到的增益能够使物理系统正常工作 调节pid的理论分析 pid的一般形式如下图 经过移动化简可以得到 现在我们的问题就简化成了在哪里放置这两个极点,和设置多大的增益? 在给微分器加上滤波器,相当于系统多了一个极点,滤波器的相关内容之后介绍 MATLAB仿真 仿真使用的模型还是我们上一篇使用的电机模型 随便取一个之前的模型进行pid控制仿真 先初始化电机模型的变量,再加上pid的必要模型,开始仿真 随便调了几下pid参数,得到下图的效果 调节零点位置和增益的方法 新名词介绍 根轨迹图(root locus)是控制理论及稳定性理论中,绘图分析的方式,可以看到在特定参数(一般会是反馈系统的环路增益)变化时,系统极点的变化。 说实话,这东西以前我听都没听过,在经过线上线下查找资料才算知道了这么个东西。 简单的说,这个图可以用来判断非时变系统系统的稳定性,以及计算系统增益并实现它的控制器 手画这个图是有许多规则的,不过我没有去了解,毕竟我时间也不多,只知道可以用MATLAB画 进入主题 有两种方法用于调节:Pole placement 和 Loop shaping Pole placement 一个简单的开环系统,他的根轨迹图是这样的 在加入PID后,会引入新的零点和极点,就会变成这样 这种调节方法就是通过调节增益,从而得到希望的系统性能 Loop shaping 这个方法和上面的类似,换了种形式的图 据论文介绍,这两种方法的性能都是差不多的,loop-shaping多了两个优点,(i)不需要在FRF上拟合LTI模型来设计控制器,并且(ii)随着控制器系数的平滑变化,增益调度的实现更加缓慢。 对于我来说,暂时只管怎么用,好不好用,就没有深入学习了 MATLAB仿真 下图是我用之前的模型随意调的pid的阶跃响应,可以看出是不符合我们的期望的,下面我们就使用MATLAB进行pid调节 我们首先需要做的是打开analysis->control design->control system designer,然后按照下面三张图所示,添加需要调节的pid模块,添加需要的信号 在control system designer的菜单栏中点击tuning methods,在下拉框中选择root locus editor,就可以得到下图 在new plot下选择new step,在弹出窗口按下图配置 最终效果如下 手动pid调节 手动调节说实话我是不太懂,我这里只是随便乱调一下表示可以手动修整而已 这里使用的是pole placement的方法,loop shaping也是类似的 自整定pid 这里主要还是介绍自整定pid,毕竟方便,不需要懂太多相关知识 在tuning methods下选择pid tuning 可以在弹出窗口中选择pid控制器的类型、性能等等,最后附上调节效果图 最后弄完后要在菜单栏选择update blocks 结尾 调节好的模型已上传github的项目库 参考资料 Design Compensator Using Automated PID Tuning and Graphical Bode Design

十进制与二进制之间转换详解

文章目录 十进制与二进制之间转换详解(一)十进制数转二进制数1.1 十进制正整数转二进制1.2 十进制负整数转二进制1.3 十进制小数转二进制数 (二) 二进制数转成十进制数2.1 二进制整数转十进制2.1 二进制小数转十进制 (三)十进制正整数转八进制 十进制与二进制之间转换详解 (一)十进制数转二进制数 1.1 十进制正整数转二进制 【基本原理】:除基数倒取余数法。 即:十进制转二进制,基数就是2,用2整除一个十进制正整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数;如此进行,直到商为0;然后把先得到的余数作为二进制数的低位有效位,把后得到的余数作为二级制的高位有效位,依次排列起来。所谓有效位,就是不算前导0; 注:计算机内部表示数的字节单位是定长的,如8位,16位,32位。所以,位数不够时,高位补0, 例如:输入十进制正整数:150 150 #include<iostream> using namespace std; int main() { int i, j;//定义循环变量; int a[1005];//定义一个储存二进制的数组; int num; cin >> num;//输入需要转换的10进制正整数; for (i = 0; num != 0; i++) { a[i] = num % 2;//对num取余.......就是除以2的余数; num = num / 2;//......每次取余之后num除以2的商; } for (j = i - 1; j >= 0; j--)//倒序输出余数,即为二进制数; { cout << a[j]; } cout << "

使用Powermock工具mock静态方法代码示例

对于Mockito和Powrmock的一些使用介绍和配置可以看Mockito配合powermock工具mock构造函数这篇文章。 假如有Demo类的getName方法需要做单元测试,代码如下: public class Demo { public String getName() { String name = "name"; String str1 = "str1", str2 = "str2"; if (name.equals(Tools.concat(str1, str2))) { name = "str"; } return name; } } 如果测试的时候并不需要关心Tools.concat(str1,str2)结果,所以需要对concat方法mock。 Tools类的代码如下: public class Tools { public static String concat(String str1, String str2) { return str1 + str2; } } 测试代码示例如下: @RunWith(PowerMockRunner.class) @PrepareForTest({Tools.class}) public class DemoTest { @Test public void testGetName() { // 注意使用mockStatic,把这个类的静态方法都mock了 PowerMockito.mockStatic(Tools.class); PowerMockito.when(Tools.concat("str1", "

Bluetooth技术学习笔记 ——蓝牙数据传输架构

参考:蓝牙协议 core_v5.0 LMP:Link Manager Protocol,链路管理协议 PBD:Profile Broadcast Data piconet:微微网 asynchronous:异步 isochronous :实时 1. 数据传输架构 数据传输架构如下图所示: (1)物理层:物理传输、物理信道和物理链路 物理传输:物理信道:物理链路: (2)逻辑层:逻辑传输和逻辑链路 逻辑传输:逻辑链路: (3)L2CAP 2. 数据流承载 (1)后缀说明,传输的数据类型 -C: for control links carrying LMP or LL messages-U:for L2CAP links carrying user data(L2CAP PDUs)-S:for stream links carrying unformatted synchronous or isochronous data (2)Framed Data Traffic:利用L2CAP层对应用层数据以帧结构的方式进行异步或实时传输。 应用层数据以变长帧的方式进行传输,帧的最大长度由协商的决定。L2CAP提供面向连接的和非面向连接的数据传输。 (3)Unframed Data Traffic:利用SCO-S、eSCO-S或PBD逻辑链路对应用层数据进行实时的、恒速的传输。 传输特点: ① 保留物理信道带宽 ② 提供锁定到微微网时钟的固定传输速率 ③ 固定的数据包大小 ④ 固定的传输间隔 SCO和eSCO发送端和接收端的关系是一对一,PBD是一对多。若应用层数据是实时的,速率可变的,只能以帧结构的形式通过L2CAP广播信道进行传输。LE系统不支持非帧结构的数据流传输模式。 (4)数据传输的可靠性 BR/EDR: ① 基带数据包头采用前向纠错码(FEC)进行编码,接收端可对存在的头错误进行纠正。 ② 接收端利用头错误检查(HEC)来检查纠错后是否依然残留错误。

JSP内置对象使用案例——编写两个JSP页面,对表单数据访问提取

1、编写2个jsp页面 1)research.jsp页面,要求: 按照以上布局,完成表单和控制的使用,标*的不能为空。 2)view.jsp 要求:获取页面提交过来的信息,并将信息显示在浏览器中。对姓名、年龄、邮箱三个文本框的值进行判断,如果为null或空将跳转回research.jsp页面,考虑不能越过research.jsp页面直接访问当前view.jsp页面的问题。 1.新建research.jsp、view.jsp文件 2.research.jsp文件代码 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> <title>research.jsp页面</title> </head> <body> <form action="view.jsp" method="post" name=form > <font size="5">个人信息调查表(*为必填项目)</font><br> 姓名:<input type="text" value=""name="name"><font color=red>*</font><br> 年龄:<input type="text"value="" name="age"><font color=red>*</font><br> 学历: <select name="xueli"> <Option selected value="专科">专科 <Option selected value="硕士">硕士 <Option selected value="本科">本科 </select><br> Email:<input type="text" value=""name="email"><font color=red>*</font><br> 爱好: <input type="checkbox"name="item"value="运动">运动 <input type="checkbox"name="item"value="旅游">旅游 <input type="checkbox"name="item"value="服装">服装<br> <input type="checkbox"name="item"value="阅读">阅读 <input type="checkbox"name="item"value="音乐">音乐 <input type="checkbox"name="item"value="购物">购物<br> 对本站的评价: <input type="radio" name="R"value="good" checked=default>好 <input type="radio" name="

TextView限制行数,每行限制字符数

android:lines="2" 表示限制2行; android:maxLength="8" 表示限制8个字符; android:ellipsize="end" 表示显示不全时使用省略号结尾; android:singleLine="true" 表示限制单行显示; =================================分割线======================= 1、android:lineSpacingExtra 设置行间距,如”10dp”。 表示额外的行间距数值,单位通常为dp,值可以为负数,小数和0。如果值为正数表示增加行间距;如果值为负数表示减少行间距;如果值为0,则没有 变化。 在java代码中 2、android:lineSpacingMultiplier 设置行间距的倍数,如”1.5或者2″ 表示行间距的倍数,没有单位,值可以为任意浮点数。如果值大于1.0表示增加行间距,如果值小于1.0表示减少行间距。 3. android:lineSpacingExtra和android:lineSpacingMultiplier 可以在一起对同一个TextView进行设置,同时使用时会先增加android:lineSpacingMultiplier设置的倍数,再加上android:lineSpacingExtra设置的额外间距 有些控件属性确实很容易忘记,做个笔记mark一下。

设计模式怎样解决设计问题

设计模式采用多种方法解决面向对象设计者经常碰到的问题,这里给出几个问题以及使用设计模式解决他们的方法。 1.寻找合适的对象 面向对象程序由对象组成,对象包括数据和对数据进行操作的过程,过程通常称为方法或操作,对象在收到客户的请求(或)消息后,执行相应的操作。 客户请求是使对象执行操作的唯一方法,操作又是对象改变内部数据的唯一方法。由于这些限制,对象的内部状态是被封装的,它不能被直接访问,它的表示对于对象外部是不可见的。 面向对象设计最困难的部分是将系统分解成对象集合。因为要考虑许多因素:封装、粒度、依赖关系、灵活性、性能、演化、复用、扩展等等,它们都是影响着系统的分解,并且这些因素通常还是相互冲突的。 面向对象设计方法学支持许多设计方法。你可以写出一个问题的描述,挑出名词和动词,进而创建相应的类和操作;或者,你可以关注系统的协作和指责关系;或者,你可以对现实世界建模,再将分析时发现的对象转化至设计中,至于哪一种方法最好,并无定论。 设计的许多对象来源于现实世界的分析建模。但是,设计结果所得到的类通常在现实世界中并不存在,有些是像数组之类的低层类,而另一些层次较高。例如,Composite模式引入了统一对待现实世界中并不存在的对象的抽象方法。严格反映当前现实世界的模型并不能产生反映将来世界的系统。设计中的抽象对于生产灵活的设计是至关重要的。 设计模式帮你确定并不明显的抽象和描述这些抽象的对象。例如,描述过程或算法的对象现实中并不存在,但他们却是设计的关键部分。Strategy模式描述了怎样实现可互换的算法族。State模式将实体的每一个状态描述为一个对象。这些对象在分析阶段,甚至在设计阶段的早期都并不存在,后来为使设计更灵活,复用性更好才将它们发掘出来。 2.决定对象的粒度 对象在大小和数目上变化极大,它们能表示下至硬件或上至整个应用的任何事物。那么我们怎样决定一个对象应该使什么呢? 设计模式很好的讲述了这个问题。 Facade模式描述了怎样用对象表示完整的子系统,Flyweight模式描述了如何支持大量最小粒度的对象。其他一些设计模式描述了将一个对象分解成许多小对象的特定方法。 Abstract Factory和Builder产生那些专门负责生成其他对象的对象。Visitor和Command生成的对象专门负责实现对其他对象或对象组的请求。 3.指定对象接口 对象声明的每一个操作指定操作名,作为参数的对象和返回值,这就是所谓的操作的型构(signature) 。对象操作所定义的所有操作型构的集合被称为该对象的接口(interface)。对象接口描述了该对象所能接受的全部请求的集合,任何匹配对象接口中型构的请求都可以发送给该对象。 类型(Type)是用来标识特定接口的一个名字。 如果一个对象接受 “window”接口所定义的所有操作请求,那么我们就说该对象具有“window”类型。一个对象可以有恀类型,并且不同的对象可以共享同一个类型。对象接口的某部分可以用某个类型来刻画,而其他部分可以用其他类型刻画。两个类型相同的对象只需要共享他们的部分接口。接口可以包含其他接口作为子集。当一个类型的接口包含另一个类型的接口时,我们就说他是另一个类型的子类型(subtype)另一个类型称之为它的超类型(supertype) 我们常说子类型继承了它的超类型的接口。 在面向对象系统中,接口是基本的组成部分。对象只有通过它们的接口才能于外部交流,如果不通过对象的接口就无法知道对象的任何事情,也无法请求对象做任何事情。对象接口与其功能实现是分离的,不同对象可以对请求做不同的实现,也就是说,两个有相同接口的对象可以有完全不同的实现。 当给对象发送该请求时,所引起的具体操作既与请求本身有感又与接受对象有关。支持相同请求的 不同对象可能对请求激发的操作又不同的实现。发送给对象的请求和它的相应操作在运行时刻的连接就称之为动态绑定(dynamic binding)。 动态绑定是指发送的请求直到运行时刻才受你的具体实现的约束。因而,在知道任何有正确接口的对象都将接受此请求时,你可以写一个一般的程序,它期待着那些具有该特定接口的对象。进一步讲,动态绑定允许你在运行时刻彼此替换有相同接口的对象。这种可替换性就称为多态(polymorphism),它是面向对象系统中的核心概念之一。多态允许客户对像仅要求其他对象支持特定接口,除此之外对其假设几乎近于无。多态简化了客户的定义,使得对象间彼此独立,并可以在于运行时刻改变它们相互的关系。 设计模式通过确定接口的主要组成成分及经接口发送的数据类型,来帮助你定义接口。设计模式也许还会告诉你接口中不应该包括哪些东西,Memento模式是一个很好的例子,它描述了怎样封装和保存对象内部的状态,以便一段时间后对象能够恢复到这一状态。它规定了Memento对象必须定义两个接口:一个允许客户保持和复制Memento的限制接口,和一个只有原对象才能使用的用来存储和提取memento中状态的特权接口。 设计模式也制定了接口之间的关系,例如,Decorator和Proxy模式要求Decorator和Proxy对象的接口与被修饰的对象和受委托的对象一致,而Visitor模式中,Visitor接口必须反映出visitor能访问的对象的所有的类。 2019-04-12:0点。 4.描述对象的实现 我们很少提及到实际上怎么定义一个对象。对象的实现是由它的类决定的,类指定了对象内部的数据和表示,也定义了对象所能完成的操作。 对象通过实例化类来创建,此对象被称为该类的实例。当实例化类时,摇滚i对象的内部数据(由实例变量组成)分配存储空间,并将操作与这些数据联系起来。对象的许多类似实例是由实例化同一个类来实现的。 新的类可以由已存在的类通过继承(class inheritance)来定义,当子类(subclass)继承父类(parentclass)时,子类包含了父类定义的所有的数据和操作。 子类的实例对象包含所有子类和父类定义的数据,且它们能够完成子类和父类定义的所有操作。 抽象类(abstract class)的主要目的是为它的子类定义公共接口。 一个抽象类将把它的部分或全部擦偶哦真的实现延迟到子类中。因此,一个抽象类不能被实例化。在抽象类中定义却没有实现的擦欧总被成为抽象操作(abstract operation),非抽象类被称为具体类(concrete class)。 子类能够改进和重更新定义它们父类的操作。更具体地说,类能够重定义(override)父类定义的操作,重定义使得子类能接管父类对请求的处理操作。 类继承允许你只需简单的扩展其他类就可以定义新类,从而可以很容易地定义具有相近功能地对象族。 混入类(mixin class)是给其他类提供可选择的接口或功能地类,它与抽象类一样不能被实例化,混入类要求多继承。 1.类继承与接口继承的比较: 理解对象的类(class)与对象的类型(type)之间的差别非常重要。 一个对象的类定义了对象是怎样实现的,同时也定义了对象的内部状态和操作的实现。但是对象的类型只与它的接口有关,接口即对象能够响应的请求的集合。一个对象可以有多个类型,不同类的对象可以有相同的类型。 当然,对象的类和类型是有紧密关系的。因为类定义了对象所能执行的操作,也定义了对象的类型。当我们说一个对象是一个类的实例时,即指该对象支持类所定义的接口。 理解类继承和接口继承(或子类型化)之间的差别也十分重要。类继承根据一个对象的实现定义了另一个对象的实现。简而言之,它是代码和标识的共享机制。然而接口继承(或子类型化)描述了一个对象什么时候能被用来替代另一个对象。 2.对接口编程,而不是对实现编程。 类继承是一个通过复用父类功能而扩展应用功能的基本机制。它允许你根据旧对象款苏定义新对象。它允许你从已存在的类中继承所需要的绝大部分功能,从而几乎无需任何代价就可以获得新的实现。 然而,实现的复用只是成功的一半,继承所拥有的定义具有相同接口的对象组的能力也是很重要的(通常可以从抽象类来继承)。为什么,因为多态依赖于这种能力。 当继承被恰当的使用时,所有从抽象类到处的类将共享该抽象类的接口。这意味着子类仅仅添加或重定义操作,而没有隐藏父类的操作。这时,所有的子类都能响应抽象类接口中的请求,从而子类的类型都是抽象类的子类型。 只根据抽象类中定义的接口来操作对象有一下两个好处: 1)客户无需知道它们使用对象的特定类型,只须对象有客户所期望的接口。 2)客户无需知道它们使用的对象是什么类来实现的,它们只须知道定义接口的抽象类。 这将极大的减少子系统实现之间的相互依赖关系,也产生了可复用的面向对象设计的如下原则: 针对接口编程,而不是针对实现编程。 不将变量声明为偶个特定聚类的实例对象,而是让它遵从抽象类所定义的接口。这是本书设计模式的一个常见主题。 当你不得不在系统的某个地方实例化具体的类(即指定一个特定的实现时),创建型模式 (Abstract factory ,Builder,Factory Method,Prototype,Singlenton)可以帮你。通过抽象对象的创建过程,这些模式提供不同方式以在实例化时建立接口和实现的透明连接。创建型模式确保你的系统是采用针对接口方式书写的,而不是针对实现书写的。 2019-04-15:23:00 5.运用复用机制 6.关联运行时刻和编译时刻的结构 7.设计应支持变化 待续。

Excel-宏、VBA

文章目录 1 什么是VBA2 宏2.1 打开Excel的开发工具功能2.2 初级宏2.3 使用相对引用2.4 制作工资条2.5 添加表单控件 3 VBA3.1 VBA编码语法3.2 变量3.2.1 定义变量3.2.2 变量名的命名规则3.2.3 变量的赋值 3.3 数据类型3.4 常量3.5 运算符3.5.1 算术操作符3.5.2 比较运算符3.5.3 逻辑运算符3.5.4 连接操作符3.5.5 运算符优先级 3.6 MsgBox3.7 获取要操作的数据表3.8 单元格的基本操作3.9 三大结构3.9.1 顺序结构3.9.2 选择结构3.9.3 循环结构 3.10 数组3.10.1 数组的创建3.10.2 数组元素的操作3.10.3 利用循环对数组元素进行赋值和遍历3.10.4 数组常用的方法3.10.5 多维数组 3.11 函数 1 什么是VBA VBA是一种编程语言,它依托于Office软件,不能独立运行,通过VBA可以实现各种Office软件操作的自动化。通俗易懂的来说就是在Excel中想实现什么功能,就可以通过VBA语言编写的程序区实现。 2 宏 2.1 打开Excel的开发工具功能 2.2 初级宏 给成绩不及格的单元格标红 录制宏:开发工具-录制宏-添加宏名“不及格的成绩”-快捷键(可以设置快捷键,这里没有设置)-保存在(一般选择当前工作簿)-说明(可以添加这个宏的说明信息) 录制宏开始,所有的操作都会被记录 点击一个空白单元格-条件格式-突出显示-小于 设定小于60分的用浅红色填充 停止录制红选中需要筛选不及格成绩的列-点击“宏” 结果 2.3 使用相对引用 给A列的单元个标红,并且每执行一次,选中的单元格下移一次 选中A1单元格-点击“使用相对引用”-录制宏 将A1单元格的改为红色文本-选中A2单元格 因为宏会记录鼠标的所有操作,所以如果想更改一个单元格后让选中的单元格下移一个,这一步就很关键 执行宏 执行结果:每标红一次,光标下移一行 2.4 制作工资条 源数据目标数据

IPSec协议抓包详解和IPSec NAT穿越报文解析

目录 协议概述 2、IPSec作用 3、认证方式 3.1、预共享密钥 3.2、数字证书 4、ESP加密算法 4.1、ESP完整性检测 4.2、ESP防重放 4.3、ESP防窃听 5、IPSec工作原理 5.1、传输模式 5.2、隧道模式 6.1、主动模式 6.1.1、Ikev1协商 6.1.2、IPSec加密协商 6.2、野蛮模式 7、IPsec穿越NAT 7.1、IPSec穿越NAT遇到的问题 7.2、IKE身份确认及协商 7.3、穿越NAT原理抓包解释 协议概述 IP Sec全称:IP Security IPSec协议,不是一个单独的协议,而是一系列为IP网络提供完整安全性的协议和服务的集合。 IPSec协议是一个工作在IP网络层的协议 作为一个隧道协议实现了VPN通信 第三层隧道协议,可以在IP层上创建一个安全的隧道,使两个异地的私有网络连接起来,或者使公网上的计算机可以访问远程的企业私有网络。 2、IPSec作用 1、保证数据来源可靠 在IPSec通信之前双方要先用IKE认证对方身份并协商密钥,只有IKE协商成功之后才能通信。由于第三方不可能知道验证和加密的算法以及相关密钥,因此无法冒充发送方,即使冒充,也会被接收方检测出来。 2、保证数据完整性 IPSec通过验证算法保证数据从发送方到接收方的传送过程中的任何数据篡改和丢失都可以被检测。 3、保证数据机密性 IPSec通过加密算法使只有真正的接收方才能获取真正的发送内容,而他人无法获知数据的真正内容 3、认证方式 3.1、预共享密钥 预共享密钥认证是IPSec双方配置时手工指定的密钥,无需在网络中互相告知密钥 3.2、数字证书 响应端发送数字证书到客户端发送端收到响应端的数字证书后,会取出附带的数字证书,并读取证书中的发布机构(Issuer),然后从操作系统的受信任证书机构列表中查找该证书办发机构的公钥,如果找不到,说明这个证书颁发机构是个不受信任的,响应端发过来的信息是不安全的。使用上一步取到的证书颁发机构的公钥,解出数字证书,得到响应端的用户信息和数字签名发送端通过证书中指定的加密算法对响应端的用户信息进行hash加密加密后的结果和证书中解出的数字签名进行对比,如果相同,就说明这份用户信息确实是响应端的,也就是说用户信息中包含的公钥确实是响应端的后续响应端使用私钥加密数据,发送端使用公钥解密。发送端使用公钥加密,响应端使用私钥解密 4、ESP加密算法 4.1、ESP完整性检测 ESP报文最后有一个验证数据字段,数据验证字段包含完整性校验值 (ICV),也称为消息身份验证码,用于验证消息身份验证与完整性。接收方计算 ICV 值并对照发送方计算的值校验它,以验证完整性。ICV 是通过 ESP 报头、负载数据与 ESP 尾端计算的。 4.2、ESP防重放 作为可选功能,ESP还能进行防重放保护。防重放保护验证每个报文是唯一的且没有被复制,这种保护确保黑客不能拦截报文和在数据流中插入改变后的报文。 防重放的工作原理: 跟踪报文顺序号并在目的端使用一个滑动窗口。当在源和目的间建立了一条连接时,两端的计数器被初始化为0。每次有报文发送时,源给报文追加一个顺序号,目的端使用滑动窗口确定预期的顺序号。目的端验证的报文的顺序号不是复制的,并且以正确的顺序被接收。 例: 1、客户端发送ESP封装报文到服务端,序列号为81 2、服务端响应报文通过ESP加密,响应报文的序列号为81 3、客户端收到服务端发送的ESP报文后,查看ESP序列号,序列号排序正确则没有重放,排序错误则出现重放。 4.3、ESP防窃听 ESP通过3DES、DES、AES机密算法加密数据,做到防窃听功能 5、IPSec工作原理 ESP有两种模式:隧道模式和传输模式。 隧道模式将发送的整个数据报文作为一个数据整体来处理,在整段数据前加上新的IP进行传输,不修改原报文。 对于传输模式而言,需要拆解报文,对原报文的数据部分进行处理,加上ESP头部后,再装上原报文的IP部分。 5.1、传输模式 ESP处理流程: 1、 将原IP报文的IP头和数据报文部分分离,在数据报文部分的尾部添加ESP尾部。ESP尾部包含:选择的加密算法需要对明文进行填充的数据Padding、填充长度Padding Length、下一头部Next Header标注被加密的数据报文类型,例如TCP协议。

算法 | 单链表的五个常见操作

问题: 1.单链表反转:事先存好下一个节点再改变指针 2.链表中环的检测:快慢指针终会相遇 3.两个有序链表的合并:两个链表各一个指针,比较大小后加到最终的链表中(有点快排的感觉) 4.删除链表倒数第K个节点:转化为删除正数第length-K+1个节点 5.求链表的中间节点:快慢指针 思路都在代码的注释中,做链表的画张图就能更好的关注逻辑,比较直观,所以强烈建议画图来看看指针怎么走。 其中只在一种给出运行的例子,2345要运行验证在1的基础上改一改就好。 代码都已检验过没有问题,上代码: 1.单链表反转 //单链表反转 public class ListReverse { public static void main(String[] args) { ListNode node1=new ListNode(1); ListNode node2=new ListNode(2); ListNode node3=new ListNode(3); ListNode node4=new ListNode(4); ListNode node5=new ListNode(5); ListNode node6=new ListNode(6); node1.next=node2; node2.next=node3; node3.next=node4; node4.next=node5; node5.next=node6; reverse(node1); System.out.println(node6.next.val); System.out.println(node5.next.val); System.out.println(node4.next.val); System.out.println(node3.next.val); System.out.println(node2.next.val); System.out.println(node1.next); } public static class ListNode{ int val; ListNode next; ListNode(int x) { val = x; } } public static ListNode reverse(ListNode head){ //单链表反转 ListNode pre=null; ListNode now=head; ListNode next; while (now!