首页
壁纸
留言板
友链
更多
统计归档
Search
1
TensorBoard:训练日志及网络结构可视化工具
12,602 阅读
2
主板开机跳线接线图【F_PANEL接线图】
7,748 阅读
3
Linux使用V2Ray 原生客户端
6,660 阅读
4
移动光猫获取超级密码&开启公网ipv6
6,025 阅读
5
NVIDIA 显卡限制功率
3,232 阅读
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
登录
/
注册
Search
标签搜索
好物分享
学习笔记
linux
MySQL
nvidia
typero
内网穿透
webdav
vps
java
cudann
gcc
cuda
树莓派
CNN
图像去雾
ssh安全
nps
暗通道先验
阿里云
jupiter
累计撰写
358
篇文章
累计收到
72
条评论
首页
栏目
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
页面
壁纸
留言板
友链
统计归档
搜索到
358
篇与
的结果
2024-04-14
关于手机充电和快充相关的知识和问题梳理
1.手机快充协议1.1 快充协议有什么用对于手机与手机配件(如充电器、充电宝)来说,也存在这样的一种暗号,只有对上暗号了,才能进行快充,这就是快充协议。因此购买充电器的时候建议购买原装充电器,避免出现充电协议不兼容导致的充电速率上不去的问题。1.2 常见的手机品牌使用的快充协议小米/红米手机:高通QC协议、Turbo Charge(小米私有协议)苹果手机:iPhone8及以后的手机,都是PD协议(iPhone8以前的,使用的是Apple 2.4A充电协议)华为手机:FCP、SCP(这两个都是私有协议,目前18W和22.5W的已经公开,但大功率如66W的,还未公开)OPPO:VOOC、SuperVOOC(两个都是私有协议)一加(oneplus):Warp(私有协议)Realme:DART(私有协议)Vivo和IQOO:vivo超快闪充、vivo闪充、双引擎闪充(三个都是私有协议)1.3 主流快充协议1.通用的USB-PD协议(公有协议)这个是USB的标准化组织推出的一个快速充电的标准。不光是手机使用这一协议,很多笔记本等设备也是用这个充电协议。并且其他所有快充协议都要遵循PD协议,因为大家用的都是USB接口,所以只能按照它们制定的标准来。USB- PD快充协议是以Type-C作为输出接口,但不是说有Type-C接口就支持PD协议的快充。目前手机大部分都是支持USB-PD快充协议的,苹果在iphone8(plus)之后就开始支持USB-PD快充,不过需要另外配备USB C to Lighting数据线,最高达到18W的充电。而安卓手机方面,因为Type-C接口最大支持15W(5V 3A),不过在实现了USB-PD协议后,输出功率最大支持到100W(20V 5A),,所以只要你的充电接口是Type-c接口,基本都是可以支持USB-PD协议。时间协议充电规格2010年USB BC1.25V1.5A2012年7月USB PD1.0不详2014年8月USB PD2.05V 3A、9V 3A、15V3A、 20V2.25A、20V 3A、20V 5A2017年2月USB PD3.05V 3A、9V3A、15V3A、20V2.25A、 20V 3A、 20V 5A PPS: 3.3V-5.9V3A、 3.3-11V 3A、3.3-16V 3A、 3.3-21V 3A、 3.3-21V 5A2021年5月USB PD3.15V 3A、9V 3A、15V 3A、20V 3A、20V 5A<br/> PPS: 3.3-5.9V3A. 33-11V 3A、3.3-16V 3A、33-21V 3A、33-21V 5A<br/> EPR: 28V 5A、36V 5A、48V 5A AVS: 15-28V 5A、 15-36V 5A、15-48V 5A2.高通的QC协议由于高通是手机芯片的龙头,高通很早就已经在自家芯片上集成了快充协议。目前已经经历了5代,但市场主流的是QC2.0/3.0/4.0。在2013年率先发布QC1.0快充,电压电流为5V 2A,充电功率10W,节省了将近一半的充电时间从QC2.0开始开启了高电压充电时代,输出为9V、12V、20V电压档位,最高支持充电功率18W,向下兼容QC1.0;QC3.0时支持3.6-20V波动电压,最高充电功率依旧是18W,向下兼容QC2.0;QC4.0时则将电压细分0.2为一档,且加入PD快充协议,5V最大可输出5.6A,9V最大可输出3A,并且充电功率提升到了28W;QC4.0+时最高功率100W,同时可以给笔记本充电。在QC4.0的基础上向下兼容QC3.0和QC2.0。3.华为的FCP和SCP协议这两种都是华为自家的私有协议。FCP协议出得早一点,用的是跟QC2.0相似的“高压小电流”方案,输出规格是9V2A 18W。SCP协议是2016年后推出的,采用的跟OPPO相似的“低压大电流”方案。输出规格是5V 4.5A或10V 4A。后来华为又在SCP协议基础上增加了电荷泵技术,将电流从4A提升到8A,实现了充电功率40W的超级快充,后面也出现双电池充电的65W超级快充。但是SCP快充协议需要在充电线支持下才能使用,需要配备支持5A大电流的充电线。4.OPPO的VOOC和SuperVOOC闪充OPPO这个VOOC闪充相信很多人都不陌生,当时还是5V 2A的充电市场为主,OPPO另辟蹊径,喊出“充电5分钟,通话2小时”的口号,率先采用低压高电流方案,推出5V 4.5A的VOOC闪充,充电功率达22.5W。相比当时主流的高压快充,低压快充温控更好,效率更高。后来经过几次更新,现在闪充已经发展到SuperVOOC2.0版本,这是采用双电池串联方案和全新的电荷泵技术,将双电芯电压减半,兼顾安全性和效率,实现了10V 6.5A,充电功率65W的超级闪充。但由于电池系统,充电器,线材都被重新定制,所以条件比较苛刻,和华为SCP快充一样,OPPO也需要支持大电流的充电线才能支持VOOC闪充。2.手机充电功耗和实时数据测试软件Battery Guru| | |安兔兔评测-充电测试| | |3.关于手机充电相关的问题3.1 手机是否可以整晚充电不拔结论:最好不要,但是使用正版原厂的充电器,一般问题也不大。因为目前的智能手机都是使用锂电池,自带的PMU(也就是电源管理单元)能够在插上电源后自动检测当前电池电量是否需要充电;在充满电之后,PMU也会自动给出断电的信号进入待机状态;当电量下降之后就会给出充电的指示。3.2 手机还没充满电可以拔掉吗?可以。锂电池没有充电记忆的,讲究随用随充,所以没有充满也是可以停止充电的,对电池影响很小。只要不让手机长时间处于没有充满的状态之下,都是不会有什么影响的。3.3 手机可以不管剩余多少电量都可以随时充电吗是的。锂电池处于低电量时损耗比较大,因此等到电耗光再充电,这会加快它的损耗。长期处于40%~60%电量可以使电池长寿。参考资料手机快充协议是什么?一篇文章带你搞懂各个快充协议(PD、QC、FCP、SCP、VOOC) - 知乎 (zhihu.com)充电协议USB-PD、QC、FCP、SCP、VOOC有什么区别,充电宝哪个牌子好?充电宝品牌选购推荐 (zhihu.com)小米/红米手机支持的快充协议汇总及充电器(宝)兼容情况汇总(最近更新于2023年9月27日) - 知乎 (zhihu.com)手机充电“一夜不拔”,对电池到底有没有坏处呢? - 知乎 (zhihu.com)手机电量到 20% 就会提醒充电的原因是什么? - 知乎 (zhihu.com)为什么手机电量「低于20%」会提醒充电?_电池 (sohu.com)充电杂谈:同为USB-C,3A充电线与5A充电线有何不同?_哔哩哔哩_bilibili【九机学院】四分钟看懂什么是高通的快速充电技术QC 3.0_哔哩哔哩_bilibili
2024年04月14日
36 阅读
0 评论
0 点赞
2024-03-21
SSH客户端登录会话避免超时设置
1.背景通常默认公有云上的ECS远程连接,很容易断开,当你有什么事情被打断或者去操作别的机器同步做点其他事情,你会发现你SSH客户端登录窗口经常会断开掉,非常烦人,经常要重新登录。而且这时候终端会卡在那里,十分的不方便。所以在网上找了几个配置SSH的方法,能保证连接能够长时间不断开。 方法有两种,一般配置一种就可以。2.配置方式2.1 客户端配置$ vim ~/.ssh/config #添加如下内容 Host * ServerAliveInterval 60 ServerAliveCountMa 30说明:本地SSH Client每隔60s向Server端SSHD发送 keep-alive 包,如果发送30次, Server端还无回应则断开连接。2.2 服务端配置vim /etc/ssh/sshd_config然后找到下面两项:ClientAliveInterval 60 ClientAliveCountMax 30这两项默认可能是注释掉的,去掉#,然后如上设置.说明:ClientAliveInterval: 这个其实就是SSH Server与Client的心跳超时时间,也就是说,当客户端没有指令过来,Server间隔ClientAliveInterval的时间(单位秒)会发一个空包到Client来维持心跳,60表示每分钟发送一次,然后客户端响应,这样就保持长连接了保证Session有效, 默认是0, 不发送;ClientAliveCountMax:当心跳包发送失败时重试的次数,比如现在我们设置成了30,如果Server向Client连续发30次心跳包都失败了,就会断开这个session连接。参考资料保持SSH连接持续不断的配置方法-腾讯云开发者社区-腾讯云 (tencent.com)配置SSH服务远程连接空闲超时退出时间(包括SSH无法登录、登录缓慢)-腾讯云开发者社区-腾讯云 (tencent.com)
2024年03月21日
45 阅读
0 评论
0 点赞
2024-01-22
激活码
1.webstormI2A0QUY8VU-eyJsaWNlbnNlSWQiOiJJMkEwUVVZOFZVIiwibGljZW5zZWVOYW1lIjoiVU5JVkVSU0lEQURFIEVTVEFEVUFMIERFIENBTVBJTkFTIiwiYXNzaWduZWVOYW1lIjoiVGFvYmFv77yaSkVU5YWo5a625qG25r+AIOa0u+W3peS9nOWupCAgcmVuIHpodW4gZGlhbiBtaW5n77yBIiwiYXNzaWduZWVFbWFpbCI6IlJvYmJ5X1dlbmlnZXJAb3V0bG9vay5jb20iLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiJGb3IgZWR1Y2F0aW9uYWwgdXNlIG9ubHkiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IkRQTiIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiREIiLCJwYWlkVXBUbyI6IjIwMjQtMTAtMTQiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlBTIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJJSSIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNDIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IkdPIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJETSIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNGIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IkRTIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQQyIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwMjQtMTAtMTQiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkNMIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJXUyIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUkQiLCJwYWlkVXBUbyI6IjIwMjQtMTAtMTQiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJTMCIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUk0iLCJwYWlkVXBUbyI6IjIwMjQtMTAtMTQiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJTViIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJEQyIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNVIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJEUCIsInBhaWRVcFRvIjoiMjAyNC0xMC0xNCIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJQREIiLCJwYWlkVXBUbyI6IjIwMjQtMTAtMTQiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUFNJIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlBDV01QIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IlJTIiwicGFpZFVwVG8iOiIyMDI0LTEwLTE0IiwiZXh0ZW5kZWQiOnRydWV9XSwibWV0YWRhdGEiOiIwMTIwMjMxMDE4TFBBQTAwMjAwOSIsImhhc2giOiI1MDY4MjM4OC8yNDQxMzAzMDotMjMxNDI0MDkzIiwiZ3JhY2VQZXJpb2REYXlzIjo3LCJhdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJpc0F1dG9Qcm9sb25nYXRlZCI6ZmFsc2V9-TVABo8WPqQXMBwop9hR4Jao5zPeU6ZWd/B4k0rUtT8YptqYZ0qcyA1w928ovkigORlHy4uIHKc75EmfkDc7V8jLUEyysKr3XGrJe/0ghkGtqTUaZ47SWiqm6TCR21PG2CtfByT0jZjw6AspsWqwyGmFeZAKfXkuAzmJ6psJOeZvaFn4qzzkjzCDdOGOdUXPEPdkG1t4a+rxgt4Ly06yEcpFpy87mx5SO/F9sus2/ZHnVCISqRQBil8hvYsQKP9TScHjyGe6I9KhRofs2SuUHe3+Wh5cSTQH4wy6mJZP+7ImX76BnOqjPWOh4sJwUJ+I+IfjOV4iG5bu25YNV9DF2eA==-MIIETDCCAjSgAwIBAgIBDzANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTIyMTAxMDE2MDU0NFoXDTI0MTAxMTE2MDU0NFowHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyMjEwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/W3uCpU5M2y48rUR/3fFR6y4xj1nOm3rIuGp2brELVGzdgK2BezjnDXpAxVDw5657hBkAUMoyByiDs2MgmVi9IcqdAwpk988/Daaajq9xuU1of59jH9eQ9c3BmsEtdA4boN3VpenYKATwmpKYkJKVc07ZKoXL6kSyZuF7Jq7HoQZcclChbF75QJPGbri3cw9vDk/e46kuzfwpGftvl6+vKibpInO6Dv0ocwImDbOutyZC7E+BwpEm1TJZW4XovMBegHhWC04cJvpH1u98xoR94ichw0jKhdppywARe43rGU96163RckIuFmFDQKZV9SMUrwpQFu4Z2D5yTNqnlLRfAgMBAAGjgZkwgZYwCQYDVR0TBAIwADAdBgNVHQ4EFgQU5FZqQ4gnVc+inIeZF+o3ID+VhcEwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBANLG1anEKid4W87vQkqWaQTkRtFKJ2GFtBeMhvLhIyM6Cg3FdQnMZr0qr9mlV0w289pf/+M14J7S7SgsfwxMJvFbw9gZlwHvhBl24N349GuthshGO9P9eKmNPgyTJzTtw6FedXrrHV99nC7spaY84e+DqfHGYOzMJDrg8xHDYLLHk5Q2z5TlrztXMbtLhjPKrc2+ZajFFshgE5eowfkutSYxeX8uA5czFNT1ZxmDwX1KIelbqhh6XkMQFJui8v8Eo396/sN3RAQSfvBd7Syhch2vlaMP4FAB11AlMKO2x/1hoKiHBU3oU3OKRTfoUTfy1uH3T+t03k1Qkr0dqgHLxiv6QU5WrarR9tx/dapqbsSmrYapmJ7S5+ghc4FTWxXJB1cjJRh3X+gwJIHjOVW+5ZVqXTG2s2Jwi2daDt6XYeigxgL2SlQpeL5kvXNCcuSJurJVcRZFYUkzVv85XfDauqGxYqaehPcK2TzmcXOUWPfxQxLJd2TrqSiO+mseqqkNTb3ZDiYS/ZqdQoGYIUwJqXo+EDgqlmuWUhkWwCkyo4rtTZeAj+nP00v3n8JmXtO30Fip+lxpfsVR3tO1hk4Vi2kmVjXyRkW2G7D7WAVt+91ahFoSeRWlKyb4KcvGvwUaa43fWLem2hyI4di2pZdr3fcYJ3xvL5ejL3m14bKsfoOv2.全家桶UX394X3HLT-eyJsaWNlbnNlSWQiOiJVWDM5NFgzSExUIiwibGljZW5zZWVOYW1lIjoiSG9uZ2lrIFVuaXZlcnNpdHntmY3snbXrjIDtlZnqtZAiLCJsaWNlbnNlZVR5cGUiOiJDTEFTU1JPT00iLCJhc3NpZ25lZU5hbWUiOiLkvJfliJvkupEg5bel5L2c5a6kIiwiYXNzaWduZWVFbWFpbCI6ImhhbmF6YXdhbWl0b0BnbWFpbC5jb20iLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiJGb3IgZWR1Y2F0aW9uYWwgdXNlIG9ubHkiLCJjaGVja0NvbmN1cnJlbnRVc2UiOmZhbHNlLCJwcm9kdWN0cyI6W3siY29kZSI6IkdPIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSUzAiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRNIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJDTCIsInBhaWRVcFRvIjoiMjAyNC0xMi0xMyIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNVIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSU0MiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUEMiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRTIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJSRCIsInBhaWRVcFRvIjoiMjAyNC0xMi0xMyIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IlJTRiIsInBhaWRVcFRvIjoiMjAyNC0xMi0xMyIsImV4dGVuZGVkIjp0cnVlfSx7ImNvZGUiOiJSTSIsInBhaWRVcFRvIjoiMjAyNC0xMi0xMyIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiSUkiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRQTiIsInBhaWRVcFRvIjoiMjAyNC0xMi0xMyIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiREIiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6ZmFsc2V9LHsiY29kZSI6IkRDIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQUyIsInBhaWRVcFRvIjoiMjAyNC0xMi0xMyIsImV4dGVuZGVkIjpmYWxzZX0seyJjb2RlIjoiUlNWIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOnRydWV9LHsiY29kZSI6IldTIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOmZhbHNlfSx7ImNvZGUiOiJQU0kiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUENXTVAiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUlMiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiRFAiLCJwYWlkVXBUbyI6IjIwMjQtMTItMTMiLCJleHRlbmRlZCI6dHJ1ZX0seyJjb2RlIjoiUERCIiwicGFpZFVwVG8iOiIyMDI0LTEyLTEzIiwiZXh0ZW5kZWQiOnRydWV9XSwibWV0YWRhdGEiOiIwMTIwMjMxMjI4TFBBQTAwNDAwOCIsImhhc2giOiI1MjY4NzM4Ny8yNTMxODE0MTotMTUwNDg0MzkwMSIsImdyYWNlUGVyaW9kRGF5cyI6NywiYXV0b1Byb2xvbmdhdGVkIjpmYWxzZSwiaXNBdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJ0cmlhbCI6ZmFsc2UsImFpQWxsb3dlZCI6dHJ1ZX0=-YqDHrEIEaf/x1JqIdTI64AYA1IpRoYiqoZ/1YDnfpEqSFNJIC4er7K1hjUm9tFslnY2XoNRs04JSUG8CgNkTgIKA4xLyxGBufJYyHv26UKQmyf1nb1pM9XATb3pWSQ3h6o8/4x3jacVk3zbAuXt3uV6eEj2bCZvhGpATFmK1JVsSor+XgPr5aYePCtyymiyPOq33ghW5onzSI5LsQR5motHvLgWmjf0Mkutys3SmWt13YVcIe5yCzhlTNCZw++CAuRh2Fx/JXZhRt+kUqW2yLbkIo3kNEg2I31H8qya+RDJ09Qz7DsDkrIgODqX4Wbd2fy1C7Q1CcjjksvjhswnpNA==-MIIETDCCAjSgAwIBAgIBDzANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTIyMTAxMDE2MDU0NFoXDTI0MTAxMTE2MDU0NFowHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyMjEwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/W3uCpU5M2y48rUR/3fFR6y4xj1nOm3rIuGp2brELVGzdgK2BezjnDXpAxVDw5657hBkAUMoyByiDs2MgmVi9IcqdAwpk988/Daaajq9xuU1of59jH9eQ9c3BmsEtdA4boN3VpenYKATwmpKYkJKVc07ZKoXL6kSyZuF7Jq7HoQZcclChbF75QJPGbri3cw9vDk/e46kuzfwpGftvl6+vKibpInO6Dv0ocwImDbOutyZC7E+BwpEm1TJZW4XovMBegHhWC04cJvpH1u98xoR94ichw0jKhdppywARe43rGU96163RckIuFmFDQKZV9SMUrwpQFu4Z2D5yTNqnlLRfAgMBAAGjgZkwgZYwCQYDVR0TBAIwADAdBgNVHQ4EFgQU5FZqQ4gnVc+inIeZF+o3ID+VhcEwSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBANLG1anEKid4W87vQkqWaQTkRtFKJ2GFtBeMhvLhIyM6Cg3FdQnMZr0qr9mlV0w289pf/+M14J7S7SgsfwxMJvFbw9gZlwHvhBl24N349GuthshGO9P9eKmNPgyTJzTtw6FedXrrHV99nC7spaY84e+DqfHGYOzMJDrg8xHDYLLHk5Q2z5TlrztXMbtLhjPKrc2+ZajFFshgE5eowfkutSYxeX8uA5czFNT1ZxmDwX1KIelbqhh6XkMQFJui8v8Eo396/sN3RAQSfvBd7Syhch2vlaMP4FAB11AlMKO2x/1hoKiHBU3oU3OKRTfoUTfy1uH3T+t03k1Qkr0dqgHLxiv6QU5WrarR9tx/dapqbsSmrYapmJ7S5+ghc4FTWxXJB1cjJRh3X+gwJIHjOVW+5ZVqXTG2s2Jwi2daDt6XYeigxgL2SlQpeL5kvXNCcuSJurJVcRZFYUkzVv85XfDauqGxYqaehPcK2TzmcXOUWPfxQxLJd2TrqSiO+mseqqkNTb3ZDiYS/ZqdQoGYIUwJqXo+EDgqlmuWUhkWwCkyo4rtTZeAj+nP00v3n8JmXtO30Fip+lxpfsVR3tO1hk4Vi2kmVjXyRkW2G7D7WAVt+91ahFoSeRWlKyb4KcvGvwUaa43fWLem2hyI4di2pZdr3fcYJ3xvL5ejL3m14bKsfoOv
2024年01月22日
231 阅读
0 评论
2 点赞
2023-12-30
fastrcnn网络结构复现
1.backbone-restnet50import math import torch.nn as nn class Bottleneck(nn.Module): expansion = 4 def __init__(self, inplanes, planes, stride=1, downsample=None): super(Bottleneck, self).__init__() self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(planes * 4) self.relu = nn.ReLU(inplace=True) self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out class ResNet(nn.Module): def __init__(self, block, layers, num_classes=1000): #-----------------------------------# # 假设输入进来的图片是600,600,3 #-----------------------------------# self.inplanes = 64 super(ResNet, self).__init__() # 600,600,3 -> 300,300,64 self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = nn.BatchNorm2d(64) self.relu = nn.ReLU(inplace=True) # 300,300,64 -> 150,150,64 self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=0, ceil_mode=True) # 150,150,64 -> 150,150,256 self.layer1 = self._make_layer(block, 64, layers[0]) # 150,150,256 -> 75,75,512 self.layer2 = self._make_layer(block, 128, layers[1], stride=2) # 75,75,512 -> 38,38,1024 到这里可以获得一个38,38,1024的共享特征层 self.layer3 = self._make_layer(block, 256, layers[2], stride=2) # self.layer4被用在classifier模型中 self.layer4 = self._make_layer(block, 512, layers[3], stride=2) self.avgpool = nn.AvgPool2d(7) self.fc = nn.Linear(512 * block.expansion, num_classes) for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() def _make_layer(self, block, planes, blocks, stride=1): downsample = None #-------------------------------------------------------------------# # 当模型需要进行高和宽的压缩的时候,就需要用到残差边的downsample #-------------------------------------------------------------------# if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( nn.Conv2d(self.inplanes, planes * block.expansion,kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(planes * block.expansion), ) layers = [] layers.append(block(self.inplanes, planes, stride, downsample)) self.inplanes = planes * block.expansion for i in range(1, blocks): layers.append(block(self.inplanes, planes)) return nn.Sequential(*layers) def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = x.view(x.size(0), -1) x = self.fc(x) return x def resnet50(): model = ResNet(Bottleneck, [3, 4, 6, 3]) #----------------------------------------------------------------------------# # 获取特征提取部分,从conv1到model.layer3,最终获得一个38,38,1024的特征层 #----------------------------------------------------------------------------# features = list([model.conv1, model.bn1, model.relu, model.maxpool, model.layer1, model.layer2, model.layer3]) #----------------------------------------------------------------------------# # 获取分类部分,从model.layer4到model.avgpool #----------------------------------------------------------------------------# classifier = list([model.layer4, model.avgpool]) features = nn.Sequential(*features) classifier = nn.Sequential(*classifier) return features, classifier extractor,classifier = resnet50() print(extractor)Sequential( (0): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False) (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (2): ReLU(inplace=True) (3): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=True) (4): Sequential( (0): Bottleneck( (conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) (downsample): Sequential( (0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) ) (1): Bottleneck( (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (2): Bottleneck( (conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) ) (5): Sequential( (0): Bottleneck( (conv1): Conv2d(256, 128, kernel_size=(1, 1), stride=(2, 2), bias=False) (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) (downsample): Sequential( (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False) (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) ) (1): Bottleneck( (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (2): Bottleneck( (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (3): Bottleneck( (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) ) (6): Sequential( (0): Bottleneck( (conv1): Conv2d(512, 256, kernel_size=(1, 1), stride=(2, 2), bias=False) (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) (downsample): Sequential( (0): Conv2d(512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False) (1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) ) ) (1): Bottleneck( (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (2): Bottleneck( (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (3): Bottleneck( (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (4): Bottleneck( (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) (5): Bottleneck( (conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False) (bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) (relu): ReLU(inplace=True) ) ) )2.RPNimport numpy as np def generate_anchor_base(base_size=16, ratios=[0.5, 1, 2], anchor_scales=[8, 16, 32]): anchor_base = np.zeros((len(ratios) * len(anchor_scales), 4), dtype=np.float32) for i in range(len(ratios)): for j in range(len(anchor_scales)): h = base_size * anchor_scales[j] * np.sqrt(ratios[i]) w = base_size * anchor_scales[j] * np.sqrt(1. / ratios[i]) index = i * len(anchor_scales) + j anchor_base[index, 0] = - h / 2. anchor_base[index, 1] = - w / 2. anchor_base[index, 2] = h / 2. anchor_base[index, 3] = w / 2. return anchor_base # 产生特征图上每个点对应的9个base anchor def _enumerate_shifted_anchor(anchor_base, feat_stride, height, width): # 计算网格中心点 shift_x = np.arange(0, width * feat_stride, feat_stride) shift_y = np.arange(0, height * feat_stride, feat_stride) shift_x, shift_y = np.meshgrid(shift_x, shift_y) shift = np.stack((shift_x.ravel(),shift_y.ravel(), shift_x.ravel(),shift_y.ravel(),), axis=1) # 每个网格点上的9个先验框 A = anchor_base.shape[0] K = shift.shape[0] anchor = anchor_base.reshape((1, A, 4)) + \ shift.reshape((K, 1, 4)) # 所有的先验框 anchor = anchor.reshape((K * A, 4)).astype(np.float32) return anchor import matplotlib.pyplot as plt nine_anchors = generate_anchor_base() # 产生特征图上每个点对应的9个base anchor height, width, feat_stride = 38,38,16 # 特征图的shape feature_map_w,feature_map_h,feature_map_c = 38,38,16 # 生成整个特征图对应的所有的base anchor ,总计feature_map_w*feature_map_h*9个 anchors_all = _enumerate_shifted_anchor(nine_anchors,feat_stride,height,width) print(np.shape(anchors_all)) fig = plt.figure() ax = fig.add_subplot(111) plt.ylim(-300,900) plt.xlim(-300,900) # 模拟绘制特征提取之前的原图 shift_x = np.arange(0, width * feat_stride, feat_stride) shift_y = np.arange(0, height * feat_stride, feat_stride) shift_x, shift_y = np.meshgrid(shift_x, shift_y) plt.scatter(shift_x,shift_y) # 绘制特征图上像素点(pix_x,pix_y)对应原图的所有anchor pix_x,pix_y = 12,0 index_begin = pix_y*width*9 + pix_x*9 index_end = pix_y*width*9 + pix_x*9 + 9 print(index_begin) box_widths = anchors_all[:,2]-anchors_all[:,0] box_heights = anchors_all[:,3]-anchors_all[:,1] for i in range(index_begin,index_end): rect = plt.Rectangle([anchors_all[i, 0],anchors_all[i, 1]],box_widths[i],box_heights[i],color="r",fill=False) ax.add_patch(rect) plt.show()# 将RPN网络预测结果转化成建议框 def loc2bbox(src_bbox, loc): if src_bbox.size()[0] == 0: return torch.zeros((0, 4), dtype=loc.dtype) src_width = torch.unsqueeze(src_bbox[:, 2] - src_bbox[:, 0], -1) src_height = torch.unsqueeze(src_bbox[:, 3] - src_bbox[:, 1], -1) src_ctr_x = torch.unsqueeze(src_bbox[:, 0], -1) + 0.5 * src_width src_ctr_y = torch.unsqueeze(src_bbox[:, 1], -1) + 0.5 * src_height dx = loc[:, 0::4] dy = loc[:, 1::4] dw = loc[:, 2::4] dh = loc[:, 3::4] ctr_x = dx * src_width + src_ctr_x ctr_y = dy * src_height + src_ctr_y w = torch.exp(dw) * src_width h = torch.exp(dh) * src_height dst_bbox = torch.zeros_like(loc) dst_bbox[:, 0::4] = ctr_x - 0.5 * w dst_bbox[:, 1::4] = ctr_y - 0.5 * h dst_bbox[:, 2::4] = ctr_x + 0.5 * w dst_bbox[:, 3::4] = ctr_y + 0.5 * h return dst_bboxclass ProposalCreator(): def __init__(self, mode, nms_thresh=0.7, n_train_pre_nms=12000, n_train_post_nms=600, n_test_pre_nms=3000, n_test_post_nms=300, min_size=16): self.mode = mode self.nms_thresh = nms_thresh self.n_train_pre_nms = n_train_pre_nms self.n_train_post_nms = n_train_post_nms self.n_test_pre_nms = n_test_pre_nms self.n_test_post_nms = n_test_post_nms self.min_size = min_size def __call__(self, loc, score, anchor, img_size, scale=1.): if self.mode == "training": n_pre_nms = self.n_train_pre_nms n_post_nms = self.n_train_post_nms else: n_pre_nms = self.n_test_pre_nms n_post_nms = self.n_test_post_nms anchor = torch.from_numpy(anchor) if loc.is_cuda: anchor = anchor.cuda() #-----------------------------------# # 将RPN网络预测结果转化成建议框 #-----------------------------------# roi = loc2bbox(anchor, loc) #-----------------------------------# # 防止建议框超出图像边缘 #-----------------------------------# roi[:, [0, 2]] = torch.clamp(roi[:, [0, 2]], min = 0, max = img_size[1]) roi[:, [1, 3]] = torch.clamp(roi[:, [1, 3]], min = 0, max = img_size[0]) #-----------------------------------# # 建议框的宽高的最小值不可以小于16 #-----------------------------------# min_size = self.min_size * scale keep = torch.where(((roi[:, 2] - roi[:, 0]) >= min_size) & ((roi[:, 3] - roi[:, 1]) >= min_size))[0] roi = roi[keep, :] score = score[keep] #-----------------------------------# # 根据得分进行排序,取出建议框 #-----------------------------------# order = torch.argsort(score, descending=True) if n_pre_nms > 0: order = order[:n_pre_nms] roi = roi[order, :] score = score[order] #-----------------------------------# # 对建议框进行非极大抑制 #-----------------------------------# keep = nms(roi, score, self.nms_thresh) keep = keep[:n_post_nms] roi = roi[keep] return roi3.合并backbone与rpn--记为FRCNN_RPNclass FRCNN_RPN(nn.Module): def __init__(self,extractor,rpn): super(FRCNN_RPN, self).__init__() self.extractor = extractor self.rpn = rpn def forward(self, x, img_size): print(img_size) feature_map = self.extractor(x) rpn_locs, rpn_scores, rois, roi_indices, anchor = self.rpn(feature_map,img_size) return rpn_locs, rpn_scores, rois, roi_indices, anchor# 加载模型参数 param = torch.load("./frcnn-restnet50.pth") param.keys() rpn = RegionProposalNetwork(in_channels=1024,mode="predict") frcnn_rpn = FRCNN_RPN(extractor,rpn) frcnn_rpn_state_dict = frcnn_rpn.state_dict() for key in frcnn_rpn_state_dict.keys(): frcnn_rpn_state_dict[key] = param[key] frcnn_rpn.load_state_dict(frcnn_rpn_state_dict)from PIL import Image import copy def get_new_img_size(width, height, img_min_side=600): if width <= height: f = float(img_min_side) / width resized_height = int(f * height) resized_width = int(img_min_side) else: f = float(img_min_side) / height resized_width = int(f * width) resized_height = int(img_min_side) return resized_width, resized_height img_path = os.path.join("xx.jpg") image = Image.open(img_path) image = image.convert("RGB") # 转换成RGB图片,可以用于灰度图预测。 image_shape = np.array(np.shape(image)[0:2]) old_width, old_height = image_shape[1], image_shape[0] old_image = copy.deepcopy(image) # 给原图像进行resize,resize到短边为600的大小上 width,height = get_new_img_size(old_width, old_height) image = image.resize([width,height], Image.BICUBIC) print(image.size) # 图片预处理,归一化。 photo = np.transpose(np.array(image,dtype = np.float32)/255, (2, 0, 1)) with torch.no_grad(): images = torch.from_numpy(np.asarray([photo])) rpn_locs, rpn_scores, rois, roi_indices, anchor = frcnn_rpn(images,[height,width]) fig = plt.figure(dpi=200) ax = fig.add_subplot(111) ax.imshow(image) # 绘制RPN的结果 for i in range(rois.shape[0]): x1,y1,x2,y2 = rois[i] w,h = x2-x1,y2-y1 rect = plt.Rectangle([x1,y1],w,h,color="r",fill=False) ax.add_patch(rect) plt.xticks([]) plt.yticks([]) plt.show() print(anchor.shape) print(rois.shape)
2023年12月30日
39 阅读
0 评论
0 点赞
2023-12-30
Jmeter性能测试学习笔记
1.性能测试理论1.1 性能的概念1.1.1 什么是性能对于应用和软件来说,主要包括时间和资源两个维度时间:系统处理用户请求的响应时间资源:系统运行过程中,系统资源的消耗情况1.1.2 什么是性能测试?使用自动化工具,模拟不同的场景,对软件各项性能指标进行测试和评估的过程。1.1.3 性能测试的目的?评估当前系统能力寻找性能瓶颈,优化性能评估软件是否能够满足未来的需要1.2 性能测试和功能测试:1.2.1 功能测试和性能测试有什么不同?功能测试:验证系统的功能需求规格。焦点:功能(正向、逆向)性能测试:验证系统的业务需求场景。焦点:时间、资源1.2.2 功能测试和性能测试有什么关系?一般项目中,先功能测试通过后,后进行性能测试。2 性能测试分类:2.1 基准测试:(1)概念:狭义上讲:就是单用户测试。(单用户循环多次得到的数据)广义上讲:建立基准线,当系统的软硬件环境发生变化之后再进行一次基准测试以确定变化对性能的影响。(2)作用基准测试不会单独存在为多用户并发测试和综合场景测试等提供参考依据为系统/环境配置、系统优化前后的性能提升/下降提供参考指标2.2 负载测试(1)概念:通过逐步增加系统负载,确定在满足系统的性能指标(如响应时间等)情况下,找出系统所能够承受的最大负载量的测试。(2)作用系统最大负载量达到用户要求时,系统才能正式上线使用。案例:电梯行业规范:电梯从1楼到5楼(15m)的运行时间不超过24s进行负载测试:case1: 1人乘坐电梯,从1楼到5楼,运行时间为20scase2:7人乘坐电梯,从1楼到5楼,运行时间为20scase3: 13人乘坐电梯,从1楼到5楼,运行时间为20s--->[最大负载量]case4: 16人乘坐电梯,从1楼到5楼,运行时间为25sCase5: 19人乘坐电梯,从1楼到5楼,运行时间为28sCase6: 21人乘坐电梯,从1楼到5楼,运行过程中绳子断了。。。注意:通过负载测试,可以确定系统的最大负载量和极限负载量系统对外宣称的最大负载量负载测试的时间一般为1-2小时2.3 稳定性测试:(1)概念在服务器稳定运行(用户正常的业务负载下)的情况下进行长时间测试(1天-1周等),并最终保证服务器能满足线上业务需求。(2)作用系统在用户要求的业务负载下运行达到规定的时间时,系统才能正式上线使用。2.4 其它分类-压力测试背景:1、软件实际使用时,用户量超过预期(系统最大负载量),该如何反应?2、软件由于意外情况出现问题,多久能恢复?(1)概念:在强负载下的测试,查看系统在峰值情况下是否功能隐患、系统是否具有良好的容错能力和可恢复能力。(2)测试场景极限负载情况下的破坏性压力测试。高负载下的长时间的稳定性压力测试。2.5 其它分类-压力并发测试:(1)概念:并发测试(绝对并发):是指在极短的时间内,发送多个请求,来验证服务器对并发的处理能力。(2)应用场景特定活动场景,如:抢红包、秒杀、抢购等。生活中的案例:悬赏任务:做菜一西红柿炒鸡蛋(但是只有一个鸡蛋和一个西红柿)(3)与负载测试对比:负载测试:主要目的是测试高负载情况下,对系统资源的消耗,是否会耗尽的问题(双11活动)并发测试:主要目的是测试极短时间内,并发请求时,系统资源争抢的问题(抢红包、秒杀)3 性能测试的指标3.1 响应时间:指从客户端发起请求开始,到客户端接收到结果的总时间包括:服务器处理时间 + 网络传输时间3.2 并发用户数:某一时刻同时向服务器发送请求的用户数案例:淘宝系统案例—哪个是并发数?3.3 吞吐量:吞吐量(Throughput):指的是单位时间内处理的客户端请求数量,直接体现软件系统的性能承载能力。从业务角度来看单位:“业务数/小时”、“业务数/天”、“访问人数/天”、“页面访问量/天”从网络角度来看单位:“字节数/小时”、“字节数/天”从技术角度来看单位:每秒事务数(TPS)、每秒查询数(QPS)QPS:QPS(Query Per Second)每秒查询数:即控制服务器每秒处理的指定请求的数量TPS:TPS(Transactions Per Second)每秒事务数:即控制服务器每秒处理的事务请求的数量事务:即业务,页面上的一次操作,可能对应一个请求/多个请求。3.4 点击数:所有的页面元素(如:图片、链接、框架等)的请求总数量.注意:点击数是请求数,不是页面上的一次点击3.5 错误率:指系统在负载情况下,失败业务的概率注意:错误率是性能指标,是高负载下的失败业务的概率随机bug是功能bug,先解决随机bug才能进行性能测试3.6 资源利用率:(1)什么是资源利用率?系统各种资源的使用情况,“资源的使用量/总的资源可用量×100%”(2)常见资源指标有哪些?CPU使用率:不高于75%-85%内存(大小)使用率:不高于80%磁盘IO(速率):不高于90%网络(速率):不高于80%4.性能测试的流程性能测试的核心:需求分析、性能测试执行、性能分析调优4.1 需求分析4.2 性能测试计划和方案测什么项目背景测试目的测试范围谁来测进度与分工交付清单怎么测测试策略4.3 编写性能测试用例用例模板:4.4 性能测试执行4.5 性能分析和调优性能测试分析人员经过对结果的分析以后,如果不符合性能需求,则会提出性能bug,然后由开发人员进行后续的调优。提示:调优-开发人员为主导,数据库管理员、系统管理员、网络管理员、性能测试分析人员配合进行验证-性能测试人员继续进行第二轮、第三轮.的测试,与以前的测试结果进行对比,从而确定经过调整以后系统的性能是否有提升4.6 性能测试报告总结测试报告是对性能测试工作的总结,为软件后续验收和交付打下基础。测试报告的主要内容:测试工作的经过回顾缺陷分析和调优风险评估性能测试结果测试工作总结与改进5.性能测试工具介绍5.1 Loadrunner简介HP Loadrunner是一种工业级标准性能测试负载工具,可以模拟上万用户实施测试,并在测试时可实时检测应用服务器及服务器硬件各种数据,来确认和查找存在的瓶颈支持多协议:Web(HTTP/HTML)、Windows Sockets、FTP、ODBC、MS SQL Server等协议采用c语言编写优点1.多用户(支持用户以万为单位)2.详细的分析报表(以秒为单位)3.支持IP欺骗功能缺点:1.收费2.体积庞大(安装包单位GB)3.无法定制功能5.2 JMeterJMeter是Apache组织开发的基于Java的开源软件,用于对系统做功能测试和性能测试。它最初被设计用于web应用测试,但后来扩展到其他测试领域,例如静态文件、Java程序、shell脚本、数据库、FTP、 Mail等。优点:1.开源免费2.小巧(安装包50MB左右)3.丰富的学习资料和扩展组件缺点:1.不支持IP欺骗2.分析和报表能力相对于LR欠缺精度(以分钟为单位)5.3 对比相同点1.都能模拟大量用户2.都能支持多协议(常见的协议都支持,如:HTTP)3.都有监控及分析报表功能不同点结论:项目日常性能测试Jmeter足够用,出商业报告优先Loadrunner6.JMeter安装和基本使用6.1 JMeter安装安装JDK安装 JMeter下载JMeterjmeter是免安装的,下载解压配置环境变量即可使用。官网下载地址:http://jmeter.apache.org/download_jmeter.cgi环境配置(可不配)jdk1.8环境配置:Java -version 查看jdk版本。jmeter环境配置(不配置不影响)1)桌面上选择“我的电脑”(右键),高级, 环境变量, 在“系统变量”—>“新建”, 在变量名中输:JMETER_HOME,变量值中输入:D:\apache-jmeter-2.112)再修改CLASSPATH变量,变量值中添加%JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;% JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib\logkit-1.2.jar; 然后确定即可。Jmeter启动三种方式:进入JMeter安装目录下的bin目录1、双击 jmeter.bat2、双击ApacheJMeter.jar3、命令行输入:java-jar ApacheJMeter.jar启动效果6.2 JMeter常用目录介绍和汉化设置6.2.1 常用文件目录介绍Bin目录:存放可执行文件和配置文件docs目录:是JMeter的api文档,用于开发扩展组件printable_docs目录:用户帮助手册lib目录:存放JMeter依赖的jar包和用户扩展所依赖的jar包6.2.2 JMeter界面的汉化临时性:启动JMeter->选择菜单、Options'->Choose Language->Chinese(Simplified)永久性 — 修改配置文件:1.找到jMeter安装目录下的bin目录2.打开jmeter.properties文件,把第37行修改为"language=zh_CN"3.重启JMeter即可7.JMeter原件和组件介绍7.1 元件的基本介绍元件:多个类似功能组件的容器(类似于类)如上图所示,主要包括:1.取样器:发送请求2.逻辑控制器:控制语句的执行顺序3.前置处理器:对请求参数进行预处理4.后置处理器:对响应结果进行提取5.断言:检查接口的返回结果是否与预期结果一致6.定时器:设置等待7.测试片段:封装一段代码,供其他脚本调用8.配置元件:测试数据的初始化配置7.2 组件的基本介绍组件:实现独立的某个功能(类似于方法)例如:取样器的组件7.3 小结如下接口自动化脚本的实现过程对应着Jmeter哪个元件?元件与组件有什么关系?元件:多个类似功能组件的容器(类似于类)组件:容器中实现独立的某个功能(类似于方法)7.4 Jmeter元件作用域和执行顺序元件的作用域:是靠测试计划的树形结构中元件的父子关系来确定的。提示:所有的组件都是以取样器为核心来运行的。组件添加的位置不同,生效的取样器也不同作用域的原则:取样器:核心,不和其他元件相互作用,没有作用域。逻辑控制器:只对其子节点中的取样器和逻辑控制器起作用。其他元件:如果是某个取样器的子节点,则该元件只对其父节点起作用。如果其父节点不是取样器,则其作用域是该元件父节点下的其他所有后代节点(包括子节点,子节点的子节点等)。元件的执行顺序同一个作用域下不同类型元件:1.配置元件(config elements)2.前置处理程序(Per-processors)3.定时器(timers)4.取样器(Sampler)5.后置处理程序(Post-processors)6.断言(Assertions)7.监听器(Listeners)同一个作用域下多个相同类型元件:按照在测试计划中从上到下的顺序依次执行执行顺序样例正确:定时器1-请求1-定时器1-定时器2-请求2-定时器1-定时器3-请求38.Jmeter第一个案例需求:使用JMeter访问百度首页接口,并查看请求和响应信息步骤:1.启动JMeter2.在测试计划下添加线程组3.在线程组,下添加HTTP请求取样器4.填写HTTP请求的相关请求数据5·在线程组下添加查看结果树监听器6.点启动按钮运行,并查看结果9.Jmeter三个重要组件(重点)9.1 线程组作用:线程组就是控制Jmeter用于执行测试的一组用户位置:右键点击、测试计划'-->添加-->线程(用户)-->线程组特点:模拟多人操作线程组可以添加多个,多个线程组可以并行或串行取样器(请求)和逻辑控制器必须依赖线程组才能使用线程组下可以添加其他元件下组件线程组分类:普通线程组:普通的、常用的线程组,可以看做一个虚拟用户组,线程组中的每一个线程都可以理解为一个虚拟用户setUp线程组:一种特殊类型的线程组,可用于执行预测试操作tearDown线程组:一种特殊类型的线程组,可用于执行测试后工作线程组的属性:练习:如下场景如何设置线程组?模拟10个用户并行执行:----线程数模拟10个用户5s内启动完成:----线程数10,ramp-up时间:5s模拟2个用户各循环3次:----线程数:2,循环次数:3模拟2个用户运行30s:----线程数:2,循环:永远,持续时间:30s模拟2个用户等待10s后开始执行:----在上一个的基础上,增加延迟启动时间:10s9.2 HTTP请求作用:向服务器发送http及https请求位置:选中线程组->右键->添加->取样器->HTTP请求参数:案例:案例一:GET请求,URL为http://www.baidu.com/S?wd=test要求:使用HTTP请求-路径来传递get请求参数案例二:GET请求,URL为https://www.baidu.com/S?wd=test要求:使用HTTP请求-参数列表来传递get请求的参数案例三:PosT请求,URL为https://www.baidu.com/S,请求体为:wd=test(form表单)要求:使用HTTP请求-参数列表来传递POST请求的form格式参数案例四:POST请求,URL为http://www.baidu.com/s,请求体为:wd=test(form表单)要求:使用HTTP请求-消息体数据来传递POST请求的form格式参数9.3 查看结果树作用:查看HTTP请求的请求和响应结果位置:选中测试计划/线程组->右键->添加->监听器->察看结果树组成:取样结果:查看响应信息头信息、响应状态码请求:查看请求相关信息(url、方法、参数)响应:查看响应信息10.Jmeter参数化定义:使用不同的测试数据,调用相同的测试方法进行测试本质:实现测试数据与测试方法的分离。JMeter中常见的参数化方式用户定义的变量——全局变量用户参数——为每个用户分配不同的参数值CSV数据文件设置——文件方式参数化函数——随机数据数据库全局变量步骤:1.添加线程组2.添加用户定义的变量。格式:变量名-变量值3.添加HTTP请求,引用定义的变量名。格式: ${变量名}4.添加查看结果树用户参数-[在线程组配置]作用:针对同一组参数,当不同的用户来访问时,可以获取到不同的值步骤:添加线程组,设置线程数为n(表示模拟的用户数)添加用户参数第一列添加多个变量含后续每一列为一组用户的数据3.添加HTTP请求用定义的变量名。格式: ${变量名}4.添加查看结果树CSV数据文件设置作用:当不同的用户,或者同一个用户多次循环时,都可以获取到不同的值位置:测试计划-->线程组--> 配置元件--> CSV 数据文件设置步骤:1.定义csv数据文件user01,123456,0000 user02, 123456, 1111 user03, 123456, 22222.添加线程组3.添加csv数据文件设置4.添加HTTP请求,引用定义的变量名。格式: ${变量名}5.添加查看结果树函数(案例:_counter函数)为什么要使用函数参数化?性能测试时,如果模拟1000个用户,每个用户循环执行10万次添加商品操作,请求参数要求不同,该怎么做?作用:计数函数,一般做执行次数统计使用位置:在菜单中选择-->选项-->函数助手对话框设置:TRUE,每个用户有自己的计数器;FALSE,使用全局计数器Name of variable in which to store the result(optional):用于存储结果的变量名(可选)操作步骤:1.添加线程组,设置虚拟用户数和循环次数2.生成_counter函数3.添加HTTP请求,使__counter函数4添加查看结果树4种参数化方式有何不同?如何选择适当的方式?用户定义的变量:-作用:定义全局变量-局限性:每次取值(无论是否相同的用户)都是固定值用户参数:-作用:保证不同的用户针对同一组参数,可以取到不同的值-局限性:同一个用户在多次循环时,取到相同的值csv数据文件设置:-作用:保证不同的用户及同一用户多次循环时,都可以取到不同的值-局限性:需要手动进行测试数据的设置函数:-作用:保证不同的用户及多次循环时,都可以取到。的值,不需要提前设置-局限性:输入数据有特定的业务要求时无法使用(如:登录时的用户名密码)参考资料黑马程序员性能测试全套教程,4天快速入门性能测试+项目商城实战JMeter安装教程
2023年12月30日
99 阅读
0 评论
0 点赞
2023-12-30
牛客刷题笔记
mysql1.MySQL的NULL值处理方法在MySQL中不能使用 = NULL 或 != NULL 等比较运算符在列中查找 NULL 值 。要用IS NULL 或 IS NOT NULL才会进行NULL值或非NULL值得查找。2.从一张表中选取数据插入到另一张表中INSERT INTO 语句用于向一张表中插入新的行。SELECT INTO 语句从一张表中选取数据插入到另一张表中。常用于创建表的备份复件或者用于对记录进行存档。3.关系代数运算中的集合运算符和关系运算符4.having必须跟在group By后面having必须跟在group By后面,不然会报错In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'db_sql.course_sku_publish_record.id'; this is incompatible with sql_mode=only_full_group_by ... 展开5.关于mysql的insert语句insert字段名顺序与字段值顺序一致即可,可以给部分或所有字段名加``。Mysql中表student_info(id,name,birth,sex),字段类型都是varchar,插入:1018 , 赵六 , 2003-08-02 , 男;SQL正确的是()?A insert overwrite student_info values('1018' , '赵六' , '2003-08-02' , '男');B insert into student_info values(1018 , '赵六' , '2003-08-02' , '男');C insert into student_info(birth,id,name,sex) values('2003-08-02' ,'1018' , '赵六' , '男');D insert into student_info value('1018' , '赵六' , '2003-08-02' , '男');正确答案:C你的答案:D官方解析:A执行报错,插入时是insert into不是insert overwrite;B执行报错,id是varchar类型,插入的1018需要加上单引号;D执行报错,插入时是values不是value;所以C正确,字段名顺序与字段值顺序一致即可,可以给部分或所有字段名加``。知识点:数据库、SQL6.MySQL中ALTER TABLE命令的用法MySQL中ALTER TABLE命令可以修改数据表的表名或数据表的字段。但是接不同后缀意义不同,比如:要修改表名或索引名时,可以用RENAME函数;当然RENAME也可以更改列名,但是后面要加TO,且它只会更改列的名字,并不更改定义。要修改字段定义和名称,可以用MODIFY或CHANGE函数。但是MODIFY只改字段定义,不改名字;CHANGE是两个都可以修改。要修改字段默认值,可以用ALTER 字段名 SET DEFULT 更改值。1.要将employee 的表名更改为 employee_info,下面MySQL语句正确的是:A ALTER TABLE employee RENAME employee_info;B ALTER TABLE employee MODIFY employee_info;C ALTER TABLE employee ALTER employee_info;D ALTER TABLE employee CHANGE employee_info;正确答案:A你的答案:B官方解析:本题考察知识点:MySQL中ALTER TABLE命令的用法MySQL中ALTER TABLE命令可以修改数据表的表名或数据表的字段。但是接不同后缀意义不同,比如:要修改表名或索引名时,可以用RENAME函数;当然RENAME也可以更改列名,但是后面要加TO,且它只会更改列的名字,并不更改定义。要修改字段定义和名称,可以用MODIFY或CHANGE函数。但是MODIFY只改字段定义,不改名字;CHANGE是两个都可以修改。要修改字段默认值,可以用ALTER 字段名 SET DEFULT 更改值。所以根据题意,要修改表名,只能用RENAME函数,因此A正确;BCD则分别是修改字段的方法。知识点:数据库、SQL7.MySql修改表名的两种方法rename table 旧表名 to 新表名; alter table 旧表名 rename [as] 新表名8.MySQL中ALTER TABLE修改字段用法-- 新增字段 ALTER TABLE 表名 ADD COLUMN 字段名 字段类型; -- 在name字段后面新增一个age列 ALTER TABLE tuser ADD COLUMN age int(11) DEFAULT NULL COMMENT '年龄' AFTER name; # AFTER:在某字段后, BEFOR:在某字段之前 -- 在表后追加一列 ALTER TABLE tuser ADD COLUMN age int(11) DEFAULT NULL COMMENT '年龄'; -- 修改字段 ALTER TABLE tuser CHANGE name user_name varchar(32) DEFAULT NULL COMMENT '姓名'; # ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型; -- 修改字段类型 ALTER TABLE tuser MODIFY name varchar(32) DEFAULT NULL COMMENT '姓名'; # ALTER TABLE 表名 MODIFY 字段名 数据类型; -- 删除字段 ALTER TABLE tuser DROP name; # ALTER TABLE 表名 DROP 字段名;9.多表删除时,delete和from之间必须要写明想要删除记录的表名。Mysql中表student_table(id,name,birth,sex),删除name重复的id最大的记录,比如'张三'重复2次,id分别是1、2,则删除id=2的记录,保留id=1的记录。如下SQL正确的是()?A delete from student_table where id in (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) ;B delete from student_table t0inner join (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) t3on t0.id = t3.id ;C delete t0from student_table t0inner join (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) t3on t0.id = t3.id ;D delete student_tablefrom student_table t0inner join (select t2.*from(select name,count(*) as c1 from student_table GROUP BY name having c1 > 1)t1left join(select name, max(id) as id from student_table group by name ) t2on t1.name = t2.name ) t3on t0.id = t3.id ;10.COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入)而COUNT(*) 函数才返回表中的记录数11.MySQL添加用户、删除用户、授权及撤销权限创建用户 insert into mysql.user(Host,User,Password) values("localhost","test",password("1234"));这样就创建了一个名为:test 密码为:1234 的用户。注意:==此处的"localhost",是指该用户只能在本地登录,不能在另外一台机器上远程登录。如果想远程登录的话,将"localhost"改为"%",表示在任何一台电脑上都可以登录。也可以指定某台机器(例如192.168.1.10),或某个网段(例如192.168.1.%)可以远程登录。==为用户授权:授权格式:grant 权限 on 数据库.* to 用户名@登录主机 identified by "密码"; 首先为用户创建一个数据库(testDB):mysql>create database testDB;授权test用户拥有testDB数据库的所有权限(某个数据库的所有权限):mysql>grant all privileges on testDB.* to test@localhost identified by '1234'; mysql>flush privileges;//刷新系统权限表,即时生效如果想指定某库的部分权限给某用户本地操作,可以这样来写:mysql>grant select,update on testDB.* to test@localhost identified by '1234'; mysql>flush privileges; 常用的权限有select,insert,update,delete,alter,create,drop等。可以查看mysql可授予用户的执行权限了解更多内容。2.4 授权test用户拥有所有数据库的某些权限的远程操作: mysql>grant select,delete,update,create,drop on *.* to test@"%" identified by "1234"; #test用户对所有数据库都有select,delete,update,create,drop 权限。2.5 查看用户所授予的权限:mysql> show grants for test@localhost;撤销已经赋予用户的权限:revoke 跟 grant 的语法差不多,只需要把关键字 “to” 换成 “from” 即可:mysql>grant all on *.* to dba@localhost; mysql>revoke all on *.* from dba@localhost;12.drop、trustcate、delete1:处理效率:drop>trustcate>delete2:删除范围:drop删除整个表(结构和数据一起删除);trustcate删除全部记录,但不删除表结构;delete只删除数据3:高水位线:delete不影响自增ID值,高水线保持原位置不动;trustcate会将高水线复位,自增ID变为1。13.mysql select 字段重命名as可以做重命名,不过也可以省略as,空格隔开新名称即可。14.mysql设置外键todo2.java1.java中接口、接口属性、接口方法的修饰符合java接口的修饰符:abstract(默认不写。interface本身就是抽象的,加不加abstract都一样)接口中字段的修饰符:public static final(默认不写) 接口中方法的修饰符:public abstract(默认不写)2.java中的数组创建形式声明的二维数组中第一个中括号中必须要有值,它代表的是在该二维数组中有多少个一维数组。 下面哪个语句是创建数组的正确语句?( )A float f[][] = new float[6][6];B float []f[] = new float[6][6];C float f[][] = new float[][6];D float [][]f = new float[6][6];E float [][]f = new float[6][];正确答案:ABDE3.关于java继承在java中,下列对继承的说法,正确的是( )A 子类能继承父类的所有成员B 子类继承父类的非私有方法和状态C 子类只能继承父类的public方法和状态D 子类只能继承父类的方法正确答案:A官方解析:Constructors, static initializers, and instance initializers are not members andtherefore are not inherited.(构造器、静态初始化块、实例初始化块不继承)4.java线程的start()和run()的区别t.run直接执行代码,按顺序打印代码; t.start是另起线程,与当前线程同时竞争cpu资源,结果存在不确定性下面程序的运行结果是:( )public static void main(String args[]) { Thread t = new Thread() { public void run() { pong(); } }; t.run(); System.out.print("ping"); } static void pong() { System.out.print("pong"); }A pingpongB pongpingC pingpong和pongping都有可能D 都不输出E pongF ping5.java集合体系判断对错。List,Set,Map都继承自继承Collection接口。A 对B错正确答案:B你的答案:A参考答案:答案:B List,Set等集合对象都继承自Collection接口 Map是一个顶层结果,不继承自Collection接口6.this不能在static的方法中使用已知有下列Test类的说明,在该类的main方法的横线处,则下列哪个语句是正确的?()public class Test { private float f = 1.0f; int m = 12; static int n = 1; public static void main (String args[]) { Test t = new Test(); ———————— } }A t.f = 1;B this.n = 1;C Test.m = 1;D Test.f = 1;正确答案:A你的答案:BA的答案中变量虽然为private,但因为main函数在该类中,所以即使private也仍可使用,B的答案static变量不能使用this7.Java中的byte,short,char进行计算时都会提升为int类型。代码片段:byte b1=1,b2=2,b3,b6; final byte b4=4,b5=6; b6=b4+b5; b3=(b1+b2); System.out.println(b3+b6);关于上面代码片段叙述正确的是()A 输出结果:13B 语句:b6=b4+b5编译出错C 语句:b3=b1+b2编译出错D 运行期抛出异常正确答案:C你的答案:A参考答案:C. 被final修饰的变量是常量,这里的b6=b4+b5可以看成是b6=10;在编译时就已经变为b6=10了 而b1和b2是byte类型,java中进行计算时候将他们提升为int类型,再进行计算,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。 Java中的byte,short,char进行计算时都会提升为int类型。8.boolean 类型不能转换成任何其它数据类型。Java中可以将布尔值与整数进行比较吗 ?A 可以B 不可以正确答案:B你的答案:A官方解析:boolean 类型不能转换成任何其它数据类型。9.java中的char是两个字节执行如下程序代码char chr = 127; int sum = 200; chr += 1; sum += chr;后,sum的值是()备注:同时考虑c/c++和Java的情况的话A 72B 99C 328D 327正确答案:AC你的答案:Ajava中只有byte, boolean是一个字节, char是两个字节, 所以对于java来说127不会发生溢出, 输出328 但是对于c/c++语言来说, char是一个字节, 会发生溢出, 对127加一发生溢出, 0111 1111 --> 1000 0000, 1000 0000为补码-128, 所以结果为200-128=7210.java中Object类的方法有哪些?equals(Object obj): 该方法用于比较当前对象与参数对象是否相等。hashCode(): 该方法返回该对象的哈希码值。toString(): 该方法返回该对象的字符串表示。clone(): 该方法创建并返回该对象的副本。finalize(): 该方法是垃圾回收器在对该对象进行清理之前调用的方法。getClass(): 该方法返回表示此对象的运行时类(包含该对象的类的对象)的Class对象。wait(long timeout): 该方法使当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者经过指定的时间量。wait(long timeout, int nanos): 该方法使当前线程等待,直到另一个线程调用该对象的notify()或notifyAll()方法,或者经过指定的时间量和纳秒数。notify(): 该方法唤醒正在等待该对象监视器的单个线程(如果没有线程在等待,则抛出IllegalMonitorStateException异常)。notifyAll(): 该方法唤醒正在等待该对象监视器的所有线程。在JAVA中,下列哪些是Object类的方法()A synchronized()B wait()C notify()D notifyAll()E sleep()正确答案:BCD你的答案:BCDE参考答案:A synchronized Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。 B C D 都是Object类中的方法 notify(): 是唤醒一个正在等待该对象的线程。 notifyAll(): 唤醒所有正在等待该对象的线程。 E sleep 是Thread类中的方法 wait 和 sleep的区别: wait指线程处于进入等待状态,形象地说明为“等待使用CPU”,此时线程不占用任何资源,不增加时间限制。 sleep指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制。11.java中整数类型 默认为 int 带小数的默认为 double在基本JAVA类型中,如果不明确指定,整数型的默认是什么类型?带小数的默认是什么类型?A int floatB int doubleC long floatD long double正确答案:B你的答案:A参考答案:整数类型 默认为 int 带小数的默认为 double12.java访问控制修饰符default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)public : 对所有类可见。使用对象:类、接口、变量、方法protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。我们可以通过以下表来说明访问权限:修饰符当前类同一包内子孙类(同一包)子孙类(不同包)其他包publicYYYYYprotectedYYYY/N(说明)NdefaultYYYNNprivateYNNNN13.java中创建线程的方法实现Runnable接口:这是最常用的方法。创建一个实现了Runnable接口的类,然后实现run()方法。这个run()方法将包含线程应该运行的代码。然后,创建一个Thread对象,并将Runnable对象作为参数传递给Thread的构造函数。最后,调用Thread对象的start()方法来启动线程。继承Thread类:这是另一种创建线程的方法,但是通常不推荐使用,因为Java不支持多重继承。创建一个继承了Thread类的类,然后重写run()方法。然后,创建一个Thread对象,并调用start()方法来启动线程。使用Callable和Future:这是一种更现代的方法,主要用于并发编程。Callable接口与Runnable接口类似,但Callable可以返回结果并且可以抛出异常。Future接口代表异步计算的结果。通过使用ExecutorService,你可以执行Callable任务并获取Future对象,然后使用Future对象的get()方法获取结果。14.jvm内存:堆区栈区存储下列Java代码中的变量a、b、c分别在内存的____存储区存放。class A { private String a = “aa”; public boolean methodB() { String b = “bb”; final String c = “cc”; } }A 堆区、堆区、堆区B 堆区、栈区、堆区C 堆区、栈区、栈区D 堆区、堆区、栈区E 静态区、栈区、堆区F 静态区、栈区、栈区正确答案:C你的答案:F参考答案:答案是C a是类中的成员变量,存放在堆区 b、c都是方法中的局部变量,存放在栈区15.java流体系16.java异常体系17.java类加载过程Java类加载过程是Java虚拟机(JVM)运行时将类文件加载到内存中的过程。这个过程可以分为三个阶段:加载、链接(验证、准备、解析)和初始化。加载:这是类加载过程的第一个阶段,主要任务是加载类。JVM通过类的全限定名来获取定义此类的二进制字节流。这个过程主要通过以下几种方式完成:通过类路径(Classpath)查找类文件(.class文件)。从JAR或ZIP文件中读取,这些文件可能被放在类路径中。从网络或其他源动态加载。通过Java反射机制从已加载的类中生成。链接:这个阶段是验证、准备和解析阶段,主要任务是确保被加载的类文件的正确性,为类的静态变量分配内存并设置初始值,以及解析符号引用。验证:确保被加载的类文件的正确性,没有安全方面的隐患。准备:为类的静态变量分配内存,并设置默认的初始值。解析:将符号引用转换为直接引用。符号引用是在编译时生成的,包含了被引用的类的全限定名;而直接引用可以直接指向数据。初始化:这是类加载过程的最后一个阶段,主要任务是执行类构造器方法<clinit>()。这个方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块(但不执行其中的方法)组成的。JVM会创建Class对象,并执行<clinit>()方法。注意,类加载器在执行完这三个阶段后,会为这个类生成一个Class对象,这个Class对象在JVM中表示这个类的类型信息。每个Class对象都对应于Java虚拟机中的元空间的一个类或接口的符号引用。此外,Java类加载器有三种:启动类加载器(Bootstrap Class Loader):负责加载核心类库,如 rt.jar、resources.jar、charsets.jar等,它是其他所有类加载器的父类加载器。由于该类加载器负责加载的是核心类库,所以它是不负责扩展类的加载的。扩展类加载器(Extension Class Loader):该类加载器负责加载JRE的扩展目录(java.ext.dirs系统属性或者java.library.path)中的类库,它是ExtensionClassLoader的父类加载器。由于该类加载器是ClassLoader中的sun.misc.Launcher$ExtClassLoader的默认实现,所以一般情况下我们不需要直接使用扩展类加载器。系统类加载器(System Class Loader):也被称为应用程序类加载器(Application Class Loader),它负责在应用程序的classpath中查找并加载类。它是ClassLoader中的sun.misc.Launcher$AppClassLoader的默认实现,也是我们最常直接使用的类加载器。以下哪项不属于java类加载过程?A 生成java.lang.Class对象B nt类型对象成员变量赋予默认值C 执行static块代码D 类方法解析正确答案:B你的答案:D参考答案:不应该选D,而应该选B 类的加载包括:加载,验证,准备,解析,初始化。 选项A:生成java.lang.Class对象是在加载时进行的。生成Class对象作为方法区这个类的各种数据的访问入口。 选项B:既然是对象成员,那么肯定在实例化对象后才有。在类加载的时候会赋予初值的是类变量,而非对象成员。 选项C:这个会调用。可以用反射试验。 选项D:类方法解析发生在解析过程。18. sleep、wait、yield、join区别sleepsleep 方法是属于 Thread 类中的,sleep 过程中线程不会释放锁,只会阻塞线程,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断,sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会waitwait 方法是属于 Object 类中的,wait 过程中线程会释放对象锁,只有当其他线程调用 notify 才能唤醒此线程。wait 使用时必须先获取对象锁,即必须在 synchronized 修饰的代码块中使用,那么相应的 notify 方法同样必须在 synchronized 修饰的代码块中使用,如果没有在synchronized 修饰的代码块中使用时运行时会抛出IllegalMonitorStateException的异常yield和 sleep 一样都是 Thread 类的方法,都是暂停当前正在执行的线程对象,不会释放资源锁,和 sleep 不同的是 yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 方法只能使同优先级或更高优先级的线程有执行的机会join等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。例如:主线程创建并启动了子线程,如果子线程中药进行大量耗时运算计算某个数据值,而主线程要取得这个数据值才能运行,这时就要用到 join 方法了下列哪些操作会使线程释放锁资源?A sleep()B wait()C join()D yield()正确答案:BC你的答案:BD19.java ThreadLocalThreadLocal是Java中的一个类,它提供了线程局部变量(thread-local variables)的实现。线程局部变量允许程序员将与线程关联的特定值(通常是一个对象引用)存储在变量中。每个线程都可以拥有自己独立的变量副本,而不会与其他线程共享。ThreadLocal的主要用途是解决多线程中的数据同步问题,避免使用synchronized关键字来锁定整个方法或代码块,从而提高程序的性能。ThreadLocal的工作原理是:每个线程持有一个该变量的副本,当线程需要访问该变量时,它将获取自己的副本,而不是共享变量。因此,每个线程都可以独立地修改自己的变量副本,而不会影响其他线程的变量。ThreadLocal的使用方法如下:创建一个ThreadLocal对象:ThreadLocal<Integer> threadLocal = new ThreadLocal<>();将值设置为每个线程的变量副本:threadLocal.set(42); // 设置当前线程的变量副本为42从每个线程获取自己的变量副本:int value = threadLocal.get(); // 获取当前线程的变量副本的值在不再需要时清除当前线程的变量副本:threadLocal.remove(); // 清除当前线程的变量副本ThreadLocal在Web开发中经常被用于存储每个请求的上下文信息,例如用户信息、会话信息等。这样,每个请求都可以有自己的独立上下文,而不会与其他请求共享。20.关于HashMap的知识点a) HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap的底层结构是一个数组,数组中的每一项是一条链表。 b) HashMap的实例有俩个参数影响其性能: “初始容量” 和 装填因子。 c) HashMap实现不同步,线程不安全。 HashTable线程安全 d) HashMap中的key-value都是存储在Entry中的。 e) HashMap可以存null键和null值,不保证元素的顺序恒久不变,它的底层使用的是数组和链表,通过hashCode()方法和equals方法保证键的唯一性 f) 解决冲突主要有三种方法:定址法,拉链法,再散列法。HashMap是采用拉链法解决哈希冲突的。21.关于java的内存区域以下描述错误的一项是( )?A 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行 到了第几行,是线程隔离的B 原则上讲,所有的对象都是在堆区上分配内存,是线程之间共享的C 方法区用于存储JVM加载的类信息、常量、静态变量,即使编译器编译后的代码等数据,是线程隔离的D Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的22.三元操作符如果遇到可以转换为数字的类型,会做自动类型提升。以下JAVA程序的运行结果是什么( )public static void main(String[] args) { Object o1 = true ? new Integer(1) : new Double(2.0); Object o2; if (true) { o2 = new Integer(1); } else { o2 = new Double(2.0); } System.out.print(o1); System.out.print(" "); System.out.print(o2); }A 1 1B 1.0 1.0C 1 1.0D 1.0 1正确答案:D你的答案:A23.类实现多个接口的时候,只需要一个implements,多个接口通过逗号进行隔开,先继承类再实现接口在java中,已定义两个接口B和C,要定义一个实现这两个接口的类,以下语句正确的是()A interface A extends B,CB interface A eimplements B,CC class A implements B,CD class A implements B,implements C正确答案:C你的答案:D24.类中实例变量可以不用初始化,使用相应类型的默认值即可;方法中的定义的局部变量必须初始化,否则编译不通过。下面代码的运行结果是()public static void main(String[] args){ String s; System.out.println("s="+s); }A 代码编程成功,并输出”s=”B 代码编译成功,并输出”s=null”C 由于String s没有初始化,代码不能编译通过。D 代码编译成功,但捕获到NullPointException异常正确答案:C你的答案:A参考答案:局部变量没有默认值25.switch支持 int及以下(char, short, byte),String, Enum 。不支持long类型在java7中,下列不能做switch()的参数类型是?A int型B 枚举类型C 字符串D 浮点型正确答案:D你的答案:B参考答案:Dswitch语句后的控制表达式只能是short、char、int整数类型和枚举类型,不能是float,double和boolean类型。String类型是java7开始支持。下面的switch语句中,x可以是哪些类型的数据:()switch(x) { default: System.out.println("Hello"); }A longB charC floatD byteE doubleF String正确答案:BDF你的答案:ABDF26.java是面向对象的,但是不是所有的都是对象,基本数据类型就不是对象,所以才会有封装类的;27.java多线程生命周期及对应的方法调用以下哪个事件会导致线程销毁?()A 调用方法sleep()B 调用方法wait()C start()方法的执行结束D run()方法的执行结束正确答案:D你的答案:C28.抛InterruptedException的代表方法有:java.lang.Object 类的 wait 方法java.lang.Thread 类的 sleep 方法java.lang.Thread 类的 join 方法29.线程安全的集合有Vector、Stack、Hashtable30. 数组无论是在定义为实例变量还是局部变量,若没有初始化,都会被自动初始化31. 发生继承关系时父子类代码执行顺序1.父类静态代码块:如果有多个静态代码块,按顺序执行,仅执行一遍2.子类静态代码块:同上3.父类非静态代码块: 有多个非静态代码块,按顺序执行,且每次new,每次执行4.父类构造函数5.子类非静态代码块: 有多个非静态代码块,按顺序执行,且每次new,每次执行6.子类构造函数32.序列化的是对象,不是类,类变量不会被序列化有以下一个对象:public class DataObject implements Serializable{ private static int i=0; private String word=" "; public void setWord(String word){ this.word=word; } public void setI(int i){ Data0bject.i=i; } }创建一个如下方式的DataObject:DataObject object=new Data0bject ( ); object.setWord("123"); object.setI(2);将此对象序列化为文件,并在另外一个JVM中读取文件,进行反序列化,请问此时读出的Data0bject对象中的word和i的值分别为:A "", 0B "", 2C "123", 2D "123", 0正确答案:D你的答案:C参考答案:这道题的答案应该是: D,序列化保存的是对象的状态,静态变量属于类的状态,因此,序列化并不保存静态变量。所以i是没有改变的33.java数组的复制效率:System.arraycopy>使用clone方法>Array.copyOf>for 循环逐一复制34.HashTable和HashMap的区别(7点):1.继承的父类不同:HashTable继承Dictory类,HashMap继承AbstractMap.但都实现了Map接口; 2.线程安全性不同:HashTable是线程安全的,适用于多线程;HashMap是非线程安全,更适合于单线程; 3.是否提供contains方法:HashTable中保留了contains方法,与constainsValue功能相同;HashMap中去掉了contains方法; 4.key和value是否可为null值:HashTable的key、value都不允许null值;HashMap,null可以作为key; 5.遍历方式的内部实现不同:HashTable、HashMap都使用了Iterator,HashTable还使用过Enumeration方式;6.hash值不同:HashTable直接使用对象的hashCode,而HashMap重新计算hash值。 7.内部使用的数组初始化和扩容方式不同:Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂;Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。35.Math 类三个用于数值处理的静态方法:ceil(), floor() 和 round().ceil()Math.ceil() 方法返回大于或等于给定数字的最小整数。换句话说,它会将给定的数字向上取整。floor()Math.floor() 方法返回小于或等于给定数字的最大整数。换句话说,它会将给定的数字向下取整。round()Math.round() 方法将给定的数字四舍五入为最接近的整数。36.关于父子类方法重写的错题:class Car extends Vehicle { public static void main (String[] args) { new Car(). run(); } private final void run() { System. out. println ("Car"); } } class Vehicle { private final void run() { System. out. println("Vehicle"); } }下列哪些针对代码运行结果的描述是正确的?A CarB VehicleC Compiler error at line 3D Compiler error at line 5E Exception thrown at runtime正确答案:A你的答案:D参考答案:答案:A 首先final声明的方法是不能被覆盖的,但是这里并不错误,因为方法是private的,也就是子类没有继承父类的run方法,因此子类的run方法跟父类的run方法无关,并不是覆盖。new Car().run()也是调用子类的run方法。37.Java ArrayList扩容在 Java 中,ArrayList 是一种动态数组,其大小(即容量)可以根据需要自动增长。当你向 ArrayList 中添加元素,并且当前的容量不足以容纳新的元素时,ArrayList 会自动进行扩容。下面是 ArrayList 扩容的基本过程:初始化容量:当你创建一个新的 ArrayList 时,你可以指定一个初始容量。如果你不指定,它会使用默认容量,通常是 10。添加元素:当你使用 add 方法向 ArrayList 中添加元素时,它会检查当前数组是否有足够的空间来容纳新元素。扩容:如果当前数组已满,ArrayList 会创建一个新的数组,其容量通常是当前数组的 1.5 倍(确切地说,新容量 = 当前容量 + (当前容量 >> 1)),然后将所有现有元素复制到新数组中。添加新元素:在新数组中,将新元素添加到适当的位置。ArrayList list = new ArrayList(20);中的list扩充几次A 0B 1C 2D 3正确答案:A你的答案:B38.类的final成员变量必须满足以下其中一个条件1、在构造函数中赋值 2、初始化赋值class Foo { final int i; int j; public void doSomething() { System.out.println(++j + i); } }的输出是?A 0B 1C 2D 不能执行,因为编译有错正确答案:D你的答案:B39.定义在同一个包(package)内的类可以不经过import而直接相互使用40.static不能修饰局部变量关于下面的程序Test.java说法正确的是( )。public class Test { static String x="1"; static int y=1; public static void main(String args[]) { static int z=2; System.out.println(x+y+z); } }A 3B 112C 13D 程序有编译错误正确答案:D你的答案:B41.java标识符规则标识符的组成元素是字母(a-z,A-Z),数字(0~9),下划线(_)和美元符号($)。 标识符不能以数字开头。 java的标识符是严格区分大小写的。 标识符的长度可以是任意的。 关键字以及null、true、false不能用于自定义的标识符。下列可作为java语言标识符的是()A a1B $1C _1D 11正确答案:ABC你的答案:AC42.replaceAll()函数的第一个参数是一个正则表达式以下代码将打印出public static void main (String[] args) { String classFile = "com.jd.". replaceAll(".", "/") + "MyClass.class"; System.out.println(classFile); }A com. jdB com/jd/MyClass.classC ///////MyClass.classD com.jd.MyClass正确答案:C你的答案:B官方解析:本题有一处陷阱,replaceAll()函数的第一个参数是一个正则表达式,而"."在正则表达式中代表了全部的字符,因此"com.jd."会全部被替换成"/"。之后字符串正常拼接,输出"///////MyClass.class",答案选择C。如想仅仅替换".",就需要使用转义字符"\."知识点:Java、正则表达式43.关于java的内部类44.Java一维数组的两种初始化方法1、静态初始化int array[] = new int[]{1,2,3,4,5} // 或者 int array[] = {1,2,3,4,5} //需要注意的是,写成如下形式也是错误的 int array[] = new int[5]{1,2,3,4,5}2、动态初始化int array[] = new int[5]; array[0] = 1; array[1] = 2; array[2] = 3; array[3] = 4; array[4] = 5;静态与动态初始化的区别就在于,前者是声明的时候就初始化,后者是先声明,再动态初始化。45.List<>赋值给List<>的限制只看尖括号里边的!!明确点和范围两个概念如果尖括号里的是一个类,那么尖括号里的就是一个点,比如List<A>,List<B>,List<Object>如果尖括号里面带有问号,那么代表一个范围,<? extends A>代表小于等于A的范围,<? super A>代表大于等于A的范围,<?>代表全部范围尖括号里的所有点之间互相赋值都是错,除非是俩相同的点尖括号小范围赋值给大范围,对,大范围赋值给小范围,错。如果某点包含在某个范围里,那么可以赋值,否则,不能赋值List<?>和List 是相等的,都代表最大范围补充:List既是点也是范围,当表示范围时,表示最大范围class A {}class B extends A {}class C extends A {}class D extends B {}下面的哪4个语句是正确的?A The type List<A>is assignable to List.B The type List<B>is assignable to List<A>.C The type List<Object>is assignable to List<?>.D The type List<D>is assignable to List<?extends B>.E The type List<?extends A>is assignable to List<A>.F The type List<Object>is assignable to any List reference.G The type List<?extends B>is assignable to List<?extends A>.正确答案:ACDG你的答案:CDEG46.关于final:修饰方法影响重写,但是不影响重载final修饰方法后,方法是不可被重写的,因为它已经是“最终形态”了。但不会影响重载以下说法错误的是( )A final修饰的方法不能被重载B final可以修饰类、接口、抽象类、方法和属性C final修饰的方法也不能被重写D final修饰的属性是常量,不可以修改正确答案:AB你的答案:B47.关于java的自动类型转换和强制类型转换数据类型的转换,分为自动转换和强制转换。自动转换是程序在执行过程中 “ 悄然 ” 进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换;强制类型转换则必须在代码中声明,转换顺序不受限制。 自动数据类型转换 自动转换按从低到高的顺序转换。不同类型数据间的优先关系如下: 低 ---------------------------------------------> 高 byte,short,char-> int -> long -> float -> double运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下: 运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下:操作数 1 类型操作数 2 类型转换后的类型byte 、 short 、 charintintbyte 、 short 、 char 、 intlonglongbyte 、 short 、 char 、 int 、 longfloatfloatbyte 、 short 、 char 、 int 、 long 、 floatdoubledouble强制数据类型转换 强制转换的格式是在需要转型的数据前加上 “( )” ,然后在括号内加入需要转化的数据类型。有的数据经过转型运算后,精度会丢失,而有的会更加精确设计模式1.备忘录模式(Memento pattern)当你需要让对象返回之前的状态时(例如, 你的用户请求"撤销"), 你使用备忘录模式现在大多数软件都有撤销(Undo)的功能,快捷键一般都是Ctrl+Z。这些软件可能使用了()模式来进行。A 备忘录模式B 访问者模式C 模板方法模式D 责任链正确答案:A你的答案:Dspring1.Spring事务参考资料:Spring事务管理详解-CSDN博客Spring事务的传播属性Spring定义了7个以PROPAGATION\_开头的常量表示它的传播属性。名称值解释PROPAGATION\_REQUIRED0支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是Spring默认的事务的传播。PROPAGATION\_SUPPORTS1支持当前事务,如果当前没有事务,就以非事务方式执行。PROPAGATION\_MANDATORY2支持当前事务,如果当前没有事务,就抛出异常。PROPAGATION\_REQUIRES\_NEW3新建事务,如果当前存在事务,把当前事务挂起。PROPAGATION\_NOT\_SUPPORTED4以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。PROPAGATION\_NEVER5以非事务方式执行,如果当前存在事务,则抛出异常。PROPAGATION\_NESTED6如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION\_REQUIRED类似的操作。Spring事务的隔离级别名称值解释ISOLATION\_DEFAULT-1这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应ISOLATION\_READ\_UNCOMMITTED1这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。ISOLATION\_READ\_COMMITTED2保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。ISOLATION\_REPEATABLE\_READ4这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。ISOLATION\_SERIALIZABLE8这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。2.@Autowired注解用@Autowired注入的流程为 :1.先根据类型进行实现类的匹配,多个实现类则不适用 2.多个实现类则会变为根据名称来匹配,就是比较注入的变量名称是否与实现类的名称相同有如下接口:public interface Student{ public void introduce(); }该接口有两个实现类:@Component public class StudentImplXH implements Student { @Override public void introduce() { System.out.println("我叫小华"); } } @Component public class StudentImplXM implements Student{ @Override public void introduce() { System.out.println("我叫小明"); } }测试类中代码如下:@Autowired private Student student; @Test void StudentTest(){ student.introduce();运行测试代码,控制台会输出什么结果?( )A 我叫小华我叫小明B我叫小华C我叫小明D程序发生异常正确答案:D你的答案:C官方解析:@Autowired注解提供这样的规则,首先根据类型找到对应的Bean,如果对应类型的 Bean 不是唯一的,那么就根据属性名称和Bean的名称进行匹配。如果匹配得上,就会使用该Bean。如果还无法匹配,就会抛出异常。3.BeanFactory和FactoryBeanBeanFactory是所有Spring Bean的容器根接口,其给IoC容器提供了一套完整的规范。FactoryBean是 一种创建Bean的方式,是对Bean的一种扩展。4.Spring容器中Bean作用域• singleton:在每个Spring IoC容器中只有一个Bean实例。 • prototype:一个Bean的定义可以有多个实例。 • request:在Web应用中,为每个HTTP请求创建一个Bean实例。 • session:在Web应用中,为每个HTTP会话创建一个Bean实例。 • global session:在基于portlet的Web应用中,为每个全局HTTP会话创建一个Bean实例。数据库理论1. 在数据库系统中,产生不一致的原因数据库中可能存在不一致的数据,主要有以下三个方面:A.数据冗余;B.并发控制不当;C.故障或者错误下面选项中,在数据库系统中,产生不一致的最重要原因是( )A 数据存储量太大B 没有严格保护数据C 未对数据进行完整性控制D 数据冗余正确答案:D你的答案:C参考答案:选D 数据库中有可能会存在不一致的数据。 造成数据不一致的原因主要有: 数据冗余 如果数据库中存在冗余数据,比如两张表中都存储了用户的地址,在用户的地址发生改变时,如果只更新了一张表中的数据,那么这两张表中就有了不一致的数据。 并发控制不当 比如某个订票系统中,两个用户在同一时间订同一张票,如果并发控制不当,可能会导致一张票被两个用户预订的情况。当然这也与元数据的设计有关。 故障和错误 如果软硬件发生故障造成数据丢失等情况,也可能引起数据不一致的情况。因此我们需要提供数据库维护和数据恢复的一些措施。知识点:数据库2.数据库设计的六个阶段1、需求分析:分析用户的需求,包括数据、功能和性能需求 2、概念结构设计:主要采用E-R模型进行设计,包括画E-R图 3、逻辑结构设计:通过将E-R图转换成表,实现从E-R模型到关系模型的转换 4、数据库物理设计:主要是为所设计的数据库选择合适的存储结构和存取路径 5、数据库的实施:包括编程、测试和试运行 6、数据库运行与维护:系统的运行与数据库的日常维护
2023年12月30日
60 阅读
4 评论
0 点赞
2023-11-29
移动光猫获取超级密码&开启公网ipv6
1.移动光猫获取超级密码本人采用的光猫型号:烽火吉比特HG6145F;所在地区:广东免责声明:本文仅供学习交流使用,由于本文所导致的光猫任何损坏,以及造成的利益损失,作者概不承担任何责任继续阅读本文即代表同意并充分且正确理解免责声明。1.1 获取光猫MAC地址方法一:直接看光猫的背面看到这串MAC号,把它记下来,比如说68-9A-21-27-53-60,并且把所有横杠删掉,就变成了689A21275360方法二:第一种方法找不到的情况打开cmd(Windows)或者 Terminal终端(macOS)、输入:arp -a并回车,对话框会显示一堆东西,你只需要找到192.168.1.1所对应的那一串接口: 192.168.1.3 --- 0x9 Internet 地址 物理地址 类型 192.168.1.1 68-9a-21-27-53-60 动态 192.168.1.4 5c-c9-99-16-e2-49 动态 192.168.1.255 ff-ff-ff-ff-ff-ff 静态 224.0.0.22 01-00-5e-00-00-16 静态 224.0.0.251 01-00-5e-00-00-fb 静态 224.0.0.252 01-00-5e-00-00-fc 静态 227.44.184.39 01-00-5e-2c-b8-27 静态 229.241.198.220 01-00-5e-71-c6-dc 静态 231.0.254.114 01-00-5e-00-fe-72 静态 239.255.255.250 01-00-5e-7f-ff-fa 静态 255.255.255.255 ff-ff-ff-ff-ff-ff 静态这里面,你只需要看到第一行192.168.1.1,并且把 68-9a-21-27-53-60 记下来,并删除-将对应的字母变成大写即可1.2 开启Telnet1、在浏览器中输入http:/192.168.1.1/cgi-bin/telnetenable.cgi?telnetenable=1&key=2、把你刚刚编辑过的MAC加到这堆东西后面,就变成了http:/192.168.1.1/cgi-bin/telnetenable.cgi?telnetenable=1&key=54E0052A4F203、回车此时,你应该看到“telnet开启”1.3 获取超级密码打开cmd(Windows)或者 Terminal终端(macOS)输入telnet 192.168.1.1 如果提示命令不存在需要去控制面板-程序-启动或关闭windows功能启动该命令然后,在login:后面输入admin,回车,对话框会提示你输入密码在Password:后面输入Fh@加上你获取的MAC的后6位,比如说我这里就是Fh@275360这时,对话框会出现一个#(none) login: admin Password: #然后依次输入load_cli factory show admin_name show admin_pwd对话框会显示#load_cli factory Config\factorydir# show admin_name Success! admin_name=CMCCAdmin Config\factorydir# show admin_pwd Success! admin_pwd=aDm8H%MdA里面admin_name=后面的CMCCAdmin就是超级账户名,admin_pwd=后面的aDm8H%MdA就是超级密码。访问192.168.1.1,把账户名和密码输进去,就进入管理员模式啦!2.移动光猫开启公网IPV6点击“网络”→“宽带设置”→ “网络连接”,找到业务类型为上网的连接名称,将IP模式该为IPV4&IPV6,并开启NPTv6,下面的端口绑定不确定需不需要可以自己摸索尝试.配置上IPV6信息的获取前缀、获取前缀方式、获取地址方式,如下图所示然后,在网络-LAN侧地址配置-IPv6配置启动DHCPv6服务最后,重启光猫,连接WIFI或者插上网线看新获取到的IP地址是否包含IPv6地址:PS C:\Users\jupiter> ipconfig Windows IP 配置 无线局域网适配器 WLAN: 连接特定的 DNS 后缀 . . . . . . . : IPv6 地址 . . . . . . . . . . . . : 2409:8a55:89a:e0f0::2 本地链接 IPv6 地址. . . . . . . . : fe80::57a8:f619:5256:9c90%9 IPv4 地址 . . . . . . . . . . . . : 192.168.1.3 子网掩码 . . . . . . . . . . . . : 255.255.255.0 默认网关. . . . . . . . . . . . . : fe80::6a9a:21ff:fe27:5360%9 192.168.1.1也可再访问一下[IPv6 测试 (test-ipv6.com)](http://test-ipv6.com/)进行测试:参考资料2023年移动光猫获取超级密码中国移动光猫CMCC H2-3启用IPv6
2023年11月29日
6,025 阅读
0 评论
0 点赞
2023-11-04
宝塔面板一键docker部署
原始地址:GitHub - pch18-docker/baota: 宝塔面板docker部署,个人笔记,方便访问1.通过host模式运行宝塔镜像docker run -tid --name baota --net=host --privileged=true --shm-size=1g --restart always -v ~/wwwroot:/www/wwwroot pch18/baota建议使用上述host网络模式启动,不需要设置映射端口,自动映射宝塔面板全端口到外网 正常的bridge模式可能会造成网站后台不能获取用户真实ip地址.2.通过bridge模式运行宝塔镜像如果特殊情况不能使用host网络模式(macos和windows不支持host), 使用下述命令重新以bridge网络模式运行docker run -tid --name baota -p 80:80 -p 443:443 -p 8888:8888 -p 888:888 --privileged=true --shm-size=1g --restart always -v ~/wwwroot:/www/wwwroot pch18/baota3.登录方式ttp://{{面板ip地址}}:8888`初始账号 username初始密码 password实测登录失败,通过docker exec -it 容器id /bin/bash如下命令进入容器,然后执行bt根据提示修改默认用户名和密码即可。由于docker镜像的特殊性,随机密码是安装面板的时候生成的, 所有用户的随机密码其实都相同,没有随机的意义, 为了方便部署,已经去除安全入口,且设置成上述密码, 请大家登陆后第一时间修改账号密码!!4.版本命名说明pch18/baota或pch18/baota:latest等同pch18/baota:lnmppch18/baota:lnmp为最新版本的官方纯净安装的基础上安装nginx,mysql,phppch18/baota:lnp 为官方版本纯净安装的基础上安装nginx,php(不内置mysql,用于外置数据库的环境)pch18/baota:lamp 为官方版本纯净安装的基础上安装apache,phppch18/baota:lap 为官方版本纯净安装的基础上安装apache,php(不内置mysql,用于外置数据库的环境)pch18/baota:clear 为官方版本纯净安装, 不默认安装nginx,mysql,php等程序5.使用建议/www文件夹建议保存在volume卷中, /www/wwwroot建议映射到宿主机的目录下,方便上传网站代码等文件安装完成后以后可以随时使用内置升级,升级到最新版本由于面板数据都保存在持久化的卷中, 即使删除容器(不删除volumn)后重新运行, 原来的面板和网站数据都能得到保留.启动容器时自动启动所有服务如果还没有安装docker的请运行这个安装脚本 https://pch18.cn/archives/install_docker.html参考资料GitHub - pch18-docker/baota: 宝塔面板docker部署
2023年11月04日
894 阅读
0 评论
0 点赞
2023-11-03
SpringBoot集成Redisson延迟队列
0. 使用场景下单成功,30分钟未支付。支付超时,自动取消订单订单签收,签收后7天未进行评价。订单超时未评价,系统默认好评下单成功,商家5分钟未接单,订单取消配送超时,推送短信提醒1.Redisson延迟队列原理redisson 使用了 两个list + 一个 sorted-set + pub/sub 来实现延时队列,而不是单一的sort-set。sorted-set:存放未到期的消息&到期时间,提供消息延时排序功能list1:存放未到期消息,作为消息的原始顺序视图,提供如查询、删除指定第几条消息的功能(分析源码得出的,查看哪些地方有使用这个list)list2:消费队列,存放到期后的消息,提供消费整体流程(对应画图PPT链接): 结合源码分析:org.redisson.RedissonDelayedQueue#RedissonDelayedQueue 首先创建延时队列的时候,会创建一个QueueTransferTask, 在里面会订阅一个topic,订阅成功后,执行其pushTask方法,里面会查询sorted-set中100个已到期的消息,将其push到lis2中,并从sorted-set和list1中移除。(这里是为了投递历史未处理的消息)protected RedissonDelayedQueue(QueueTransferService queueTransferService, Codec codec, final CommandAsyncExecutor commandExecutor, String name) { super(codec, commandExecutor, name); channelName = prefixName("redisson_delay_queue_channel", getRawName()); queueName = prefixName("redisson_delay_queue", getRawName()); timeoutSetName = prefixName("redisson_delay_queue_timeout", getRawName()); QueueTransferTask task = new QueueTransferTask(commandExecutor.getConnectionManager()) { @Override protected RFuture<Long> pushTaskAsync() { return commandExecutor.evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_LONG, "local expiredValues = redis.call('zrangebyscore', KEYS[2], 0, ARGV[1], 'limit', 0, ARGV[2]); " + "if #expiredValues > 0 then " + "for i, v in ipairs(expiredValues) do " + "local randomId, value = struct.unpack('dLc0', v);" + "redis.call('rpush', KEYS[1], value);" + "redis.call('lrem', KEYS[3], 1, v);" + "end; " + "redis.call('zrem', KEYS[2], unpack(expiredValues));" + "end; " // get startTime from scheduler queue head task + "local v = redis.call('zrange', KEYS[2], 0, 0, 'WITHSCORES'); " + "if v[1] ~= nil then " + "return v[2]; " + "end " + "return nil;", Arrays.<Object>asList(getRawName(), timeoutSetName, queueName), System.currentTimeMillis(), 100); } @Override protected RTopic getTopic() { return RedissonTopic.createRaw(LongCodec.INSTANCE, commandExecutor, channelName); } }; queueTransferService.schedule(queueName, task); this.queueTransferService = queueTransferService; } org.redisson.RedissonDelayedQueue#offerAsync(V, long, java.util.concurrent.TimeUnit) 发送延时消息时,会将消息写入 list1和 sorted-set 中,msg会添加一个randomId,支持发送相同的消息。并且判断sorted-set首条消息如果是刚插入的,则publish timeout(到期时间) 到 topicpublic RFuture<Void> offerAsync(V e, long delay, TimeUnit timeUnit) { if (delay < 0) { throw new IllegalArgumentException("Delay can't be negative"); } long delayInMs = timeUnit.toMillis(delay); long timeout = System.currentTimeMillis() + delayInMs; long randomId = ThreadLocalRandom.current().nextLong(); return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_VOID, "local value = struct.pack('dLc0', tonumber(ARGV[2]), string.len(ARGV[3]), ARGV[3]);" + "redis.call('zadd', KEYS[2], ARGV[1], value);" + "redis.call('rpush', KEYS[3], value);" // if new object added to queue head when publish its startTime // to all scheduler workers + "local v = redis.call('zrange', KEYS[2], 0, 0); " + "if v[1] == value then " + "redis.call('publish', KEYS[4], ARGV[1]); " + "end;", Arrays.<Object>asList(getRawName(), timeoutSetName, queueName, channelName), timeout, randomId, encode(e)); }org.redisson.QueueTransferTask#scheduleTask 订阅到topic消息后,会先判断其是否临期(delay<10ms),如果是则调用pushTask方法,不是则启动一个定时任务(使用的netty时间轮),延时delay后执行pushTask方法。// 订阅topic onMessage 时调用 private void scheduleTask(final Long startTime) { TimeoutTask oldTimeout = lastTimeout.get(); if (startTime == null) { return; } if (oldTimeout != null) { oldTimeout.getTask().cancel(); } long delay = startTime - System.currentTimeMillis(); if (delay > 10) { // 使用 netty 时间轮 启动一个定时任务 Timeout timeout = connectionManager.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { pushTask(); TimeoutTask currentTimeout = lastTimeout.get(); if (currentTimeout.getTask() == timeout) { lastTimeout.compareAndSet(currentTimeout, null); } } }, delay, TimeUnit.MILLISECONDS); if (!lastTimeout.compareAndSet(oldTimeout, new TimeoutTask(startTime, timeout))) { timeout.cancel(); } } else { pushTask(); } } private void pushTask() { RFuture<Long> startTimeFuture = pushTaskAsync(); startTimeFuture.onComplete((res, e) -> { if (e != null) { if (e instanceof RedissonShutdownException) { return; } log.error(e.getMessage(), e); scheduleTask(System.currentTimeMillis() + 5 * 1000L); return; } if (res != null) { scheduleTask(res); } }); }2.SpringBoot集成实验环境:SpringBoot版本3.0.12<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.12</version> <relativePath/> <!-- lookup parent from repository --> </parent>2.1 引入 Redisson 依赖 <!--redission--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.19.0</version> </dependency>2.2 配置文件spring: data: redis: host: 172.19.236.66 port: 6379 #password: 123456 database: 0 timeout: 30002.3 创建 RedissonConfig 配置package com.example.redissionstudy.config; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author LuoJia * @version 1.0 * @description: Redis链接配置文件 * @date 2023/11/3 8:59 */ @Configuration public class RedissonConfig { @Value("${spring.data.redis.host}") private String host; @Value("${spring.data.redis.port}") private int port; @Value("${spring.data.redis.database}") private int database; //@Value("${spring.data.redis.password}") //private String password; @Bean public RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer() .setAddress("redis://" + host + ":" + port) .setDatabase(database); //.setPassword(password) return Redisson.create(config); } }测试使用@SpringBootTest @Slf4j class RedissionStudyApplicationTests { @Resource RedissonClient redissonClient; @Test void testRedission() { //字符串操作 RBucket<String> rBucket = redissonClient.getBucket("strKey"); // 设置value和key的有效期 rBucket.set("张三", 30, TimeUnit.MINUTES); // 通过key获取value System.out.println(redissonClient.getBucket("strKey").get()); } }张三redis查看结果127.0.0.1:6379> keys str* 1) "strKey" 127.0.0.1:6379> get strKey "\x03\x83\xe5\xbc\xa0\xe4\xb8\x89"2.4 封装 Redis 延迟队列工具类package com.example.redissionstudy.utils; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RBlockingDeque; import org.redisson.api.RDelayedQueue; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @author LuoJia * @version 1.0 * @description: Redission 延迟队列工具类 * @date 2023/11/3 9:51 */ @Slf4j @Component public class RedisDelayQueueUtil { @Autowired private RedissonClient redissonClient; /** * 添加延迟队列 * * @param value 队列值 * @param delay 延迟时间 * @param timeUnit 时间单位 * @param queueCode 队列键 * @param <T> */ public <T> void addDelayQueue(T value, long delay, TimeUnit timeUnit, String queueCode) { try { RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(queueCode); RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque); delayedQueue.offer(value, delay, timeUnit); log.info("(添加延时队列成功) 队列键:{},队列值:{},延迟时间:{}", queueCode, value, timeUnit.toSeconds(delay) + "秒"); } catch (Exception e) { log.error("(添加延时队列失败) {}", e.getMessage()); throw new RuntimeException("(添加延时队列失败)"); } } /** * 获取延迟队列 * * @param queueCode * @param <T> * @return * @throws InterruptedException */ public <T> T getDelayQueue(String queueCode) throws InterruptedException { RBlockingDeque<Map> blockingDeque = redissonClient.getBlockingDeque(queueCode); T value = (T) blockingDeque.take(); return value; } }2.5 创建延迟队列业务枚举package com.example.redissionstudy.enums; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; /** * @author LuoJia * @version 1.0 * @description: 延迟队列业务枚举 * @date 2023/11/3 9:53 */ @Getter @AllArgsConstructor @NoArgsConstructor public enum RedisDelayQueueEnum { ORDER_PAYMENT_TIMEOUT("ORDER_PAYMENT_TIMEOUT", "订单支付超时,自动取消订单", "orderPaymentTimeout"), ORDER_TIMEOUT_NOT_EVALUATED("ORDER_TIMEOUT_NOT_EVALUATED", "订单超时未评价,系统默认好评", "orderTimeoutNotEvaluated"); /** * 延迟队列 RedisKey */ private String code; /** * 中文描述 */ private String name; /** * 延迟队列具体业务实现的 Bean * 可通过 Spring 的上下文获取 */ private String beanId; }2.6 定义延迟队列执行器package com.example.redissionstudy.handler; /** * @author LuoJia * @version 1.0 * @description: 延迟队列执行器接口 * @date 2023/11/3 9:58 */ public interface RedisDelayQueueHandle<T>{ void execute(T t); }2.7 创建枚举中定义的Bean,并实现延迟队列执行器OrderPaymentTimeout:订单支付超时延迟队列处理类package com.example.redissionstudy.handler.impl; import com.example.redissionstudy.enums.RedisDelayQueueEnum; import com.example.redissionstudy.handler.RedisDelayQueueHandle; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.Map; /** * @author LuoJia * @version 1.0 * @description: 订单支付超时处理类 * @date 2023/11/3 10:00 */ @Component @Slf4j public class OrderPaymentTimeout implements RedisDelayQueueHandle<Map> { @Override public void execute(Map map) { log.info("{} {}", RedisDelayQueueEnum.ORDER_PAYMENT_TIMEOUT.getName(), map); // TODO 订单支付超时,自动取消订单处理业务... } } OrderTimeoutNotEvaluated:订单超时未评价延迟队列处理类package com.example.redissionstudy.handler.impl; import com.example.redissionstudy.enums.RedisDelayQueueEnum; import com.example.redissionstudy.handler.RedisDelayQueueHandle; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.Map; /** * @author LuoJia * @version 1.0 * @description: 订单超时未评价处理类 * @date 2023/11/3 10:01 */ @Component @Slf4j public class OrderTimeoutNotEvaluated implements RedisDelayQueueHandle<Map> { @Override public void execute(Map map) { log.info("{} {}", RedisDelayQueueEnum.ORDER_TIMEOUT_NOT_EVALUATED.getName(), map); // TODO 订单超时未评价,系统默认好评处理业务... } }2.8 创建延迟队列消费线程,项目启动完成后开启package listener; import com.example.redissionstudy.enums.RedisDelayQueueEnum; import com.example.redissionstudy.handler.RedisDelayQueueHandle; import com.example.redissionstudy.utils.RedisDelayQueueUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; /** * @author LuoJia * @version 1.0 * @description: 启动延迟队列 * @date 2023/11/3 10:02 */ @Slf4j @Component public class RedisDelayQueueRunner implements CommandLineRunner { @Autowired private RedisDelayQueueUtil redisDelayQueueUtil; @Autowired private ApplicationContext applicationContext; @Override public void run(String... args) { new Thread(() -> { while (true) { try { RedisDelayQueueEnum[] queueEnums = RedisDelayQueueEnum.values(); for (RedisDelayQueueEnum queueEnum : queueEnums) { Object value = redisDelayQueueUtil.getDelayQueue(queueEnum.getCode()); if (value != null) { RedisDelayQueueHandle redisDelayQueueHandle = (RedisDelayQueueHandle) applicationContext.getBean(queueEnum.getBeanId()); redisDelayQueueHandle.execute(value); } } } catch (InterruptedException e) { log.error("(Redis延迟队列异常中断) {}", e.getMessage()); } } }).start(); log.info("(Redis延迟队列启动成功)"); } }以上步骤,Redis 延迟队列核心代码已经完成,下面我们写一个测试接口,用 PostMan 模拟测试一下2.9 创建一个测试接口,模拟添加延迟队列package com.example.redissionstudy.controller; /** * @author LuoJia * @version 1.0 * @description: 延迟队列测试 * @date 2023/11/3 10:05 */ import com.example.redissionstudy.enums.RedisDelayQueueEnum; import com.example.redissionstudy.utils.RedisDelayQueueUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @RestController public class RedisDelayQueueController { @Autowired private RedisDelayQueueUtil redisDelayQueueUtil; @GetMapping("/addQueue") public void addQueue() { Map<String, String> map1 = new HashMap<>(); map1.put("orderId", "100"); map1.put("remark", "其他信息"); Map<String, String> map2 = new HashMap<>(); map2.put("orderId", "200"); map2.put("remark", "其他信息"); // 添加订单支付超时,自动取消订单延迟队列。为了测试效果,延迟10秒钟 redisDelayQueueUtil.addDelayQueue(map1, 10, TimeUnit.SECONDS, RedisDelayQueueEnum.ORDER_PAYMENT_TIMEOUT.getCode()); // 订单超时未评价,系统默认好评。为了测试效果,延迟20秒钟 redisDelayQueueUtil.addDelayQueue(map2, 20, TimeUnit.SECONDS, RedisDelayQueueEnum.ORDER_TIMEOUT_NOT_EVALUATED.getCode()); } }运行结果2023-11-03T10:09:46.800+08:00 INFO 21480 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2023-11-03T10:09:46.816+08:00 INFO 21480 --- [ main] c.e.r.RedissionStudyApplication : Started RedissionStudyApplication in 4.888 seconds (process running for 5.743) 2023-11-03T10:09:46.825+08:00 INFO 21480 --- [ main] c.e.r.listener.RedisDelayQueueRunner : (Redis延迟队列启动成功) 2023-11-03T10:09:47.039+08:00 INFO 21480 --- [-10.108.155.252] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2023-11-03T10:09:47.040+08:00 INFO 21480 --- [-10.108.155.252] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2023-11-03T10:09:47.042+08:00 INFO 21480 --- [-10.108.155.252] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms 2023-11-03T10:10:25.798+08:00 INFO 21480 --- [nio-8080-exec-4] c.e.r.utils.RedisDelayQueueUtil : (添加延时队列成功) 队列键:ORDER_PAYMENT_TIMEOUT,队列值:{orderId=100, remark=其他信息},延迟时间:10秒 2023-11-03T10:10:25.802+08:00 INFO 21480 --- [nio-8080-exec-4] c.e.r.utils.RedisDelayQueueUtil : (添加延时队列成功) 队列键:ORDER_TIMEOUT_NOT_EVALUATED,队列值:{orderId=200, remark=其他信息},延迟时间:20秒 2023-11-03T10:10:35.779+08:00 INFO 21480 --- [ Thread-2] c.e.r.handler.impl.OrderPaymentTimeout : 订单支付超时,自动取消订单 {orderId=100, remark=其他信息} 2023-11-03T10:10:45.860+08:00 INFO 21480 --- [ Thread-2] c.e.r.h.impl.OrderTimeoutNotEvaluated : 订单超时未评价,系统默认好评 {orderId=200, remark=其他信息}参考资料SpringBoot集成Redisson实现延迟队列 - 掘金 (juejin.cn)SpringBoot集成Redisson实现延迟队列_redssion延时队列订阅_刘鹏博.的博客-CSDN博客Maven Repository: org.redisson » redisson-spring-boot-starter (mvnrepository.com)【进阶篇】Redis实战之Redisson使用技巧详解 - 知乎 (zhihu.com)Table of Content · redisson/redisson Wiki · GitHub浅析 Redisson 的分布式延时队列 RedissonDelayedQueue 运行流程 - 掘金 (juejin.cn)Redisson分布式延时队列 RedissonDelayedQueue - 掘金 (juejin.cn)
2023年11月03日
30 阅读
0 评论
0 点赞
2023-10-29
离线安装pytorch
离线安装pytorch针对网络不稳定在线安装总是中途失败的情况下采用离线安装的方式1.安装前准备1.1 安装显卡驱动略1.2 创建虚拟环境conda create -n torch1.9 python=3.8 conda activate torch1.92.离线安装2.1 版本对应关系2.2 离线下载安装包下载地址:download.pytorch.org/whl/torch_stable.html我们在这里可以找到我们需要的torch-1.9.0+cu111-cp38-cp38-linux_x86_64.whl以及torchvision-0.10.0+cu111-cp38-cp38-linux_x86_64.whl两个文件即可。注意,cu111代表CUDA11.1,cp38表示python3.8的编译环境,linux_x86_64表示x86的平台64位操作系统。下载完成后,我们将这两个文件传入你的离线主机(服务器)中。接着进入刚刚用conda创建好的虚拟环境后依次安装whl包:2.3 离线安装# CPU版 pip install torch-1.9.0+cpu-cp38-cp38-linux_x86_64.whl pip install torchvision-0.10.0+cpu-cp38-cp38-linux_x86_64.whl # GPU版 pip install torch-1.9.0+cu111-cp38-cp38-linux_x86_64.whl pip install torchvision-0.10.0+cu111-cp38-cp38-linux_x86_64.whl参考资料Pytorch1.9 CPU/GPU(CUDA11.1)安装_torch==1.9.0+cu111_太阳花的小绿豆的博客-CSDN博客
2023年10月29日
321 阅读
0 评论
0 点赞
2023-10-28
YOLOv5 四检测头配置
一、网络结构说明Yolov5原网络结构如下:增加一层检测层后,网络结构如下:(其中虚线表示删除的部分,细线表示增加的数据流动方向)二、网络配置第一步,在models文件夹下面创建yolov5s-add-one-layer.yaml文件。第二步,将下面的内容粘贴到新创建的文件中。# YOLOv5 by Ultralytics, GPL-3.0 license # Parameters nc: 2 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple anchors: - [4,5, 8,10, 22,18] # P2/4 - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 # add feature extration layer [-1, 3, C3, [256, False]], # 17 [-1, 1, Conv, [128, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 2], 1, Concat, [1]], # cat backbone P3 # add detect layer [-1, 3, C3, [128, False]], # 21 (P4/4-minium) [-1, 1, Conv, [128, 3, 2]], [[-1, 18], 1, Concat, [1]], # cat head P3 # end [-1, 3, C3, [256, False]], # 24 (P3/8-small) [-1, 1, Conv, [256, 3, 2]], [[-1, 14], 1, Concat, [1]], # cat head P4 [-1, 3, C3, [512, False]], # 27 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # cat head P5 [-1, 3, C3, [1024, False]], # 30 (P5/32-large) [[21, 24, 27, 30], 1, Detect, [nc, anchors]], # Detect(P2, P3, P4, P5) ]第三步,正常执行新模型的训练流程,参考:快速使用YOLOv5进行训练VOC格式的数据集 - jupiter's blog (inat.top)。参考资料【Yolov5】Yolov5添加检测层,四层结构对小目标、密集场景更友好_yolov5增加小目标检测层-CSDN博客
2023年10月28日
205 阅读
0 评论
0 点赞
2023-10-28
[目标检测模型辅助数据标注]YOLOv5检测图片并将结果转为voc的xml格式
1.调用YOLOv5检测模型对图片文件夹执行检测并保存txt和confpython detect.py --weight runs\train\exp3\weights\best.pt --source [待检测的图片文件夹]--save-txt --save-conf2.将检测结果转为voc的xml格式import os import copy from xml.dom import minidom from tqdm import tqdm import cv2 import xmltodict # 图片\YOLO txt\xml对应的文件夹地址 base_dir = "[上面的待检测的图片文件夹]" img_dir = os.path.join(base_dir,"img") txt_dir = os.path.join(base_dir,"labels") xml_dir = os.path.join(base_dir,"xml") class_name_list = "YOLO项目中data.yaml的class_names" obj_base = { 'name':'name', 'bndbox':{ 'xmin':1, 'ymin':1, 'xmax':1, 'ymax':1 } } xml_base = { 'annotation': { 'folder':'img', 'filename':'', 'size':{ 'width':1, 'height':1, 'depth':3 }, 'object':[] } } img_name_list = os.listdir(img_dir) pbar = tqdm(total=len(img_name_list)) pbar.set_description("YOLOTXT2VOC:") for i in range(len(img_name_list)): # 拼接对应文件的地址 img_name = img_name_list[i] img_path = os.path.join(img_dir,img_name) txt_path = os.path.join(txt_dir,img_name.split(".")[0]+".txt") xml_path = os.path.join(xml_dir,img_name.split(".")[0]+".xml") # 初始化xml文件对象 xml_tmp = copy.deepcopy(xml_base) xml_tmp['annotation']['filename'] = img_name # 读取图片对应的宽高信息 img = cv2.imread(img_path) img_height,img_width = img.shape[:2] # 读取txt文件内容 with open(txt_path,'r') as f: content = f.read() # 逐行解析txt内容 for line in content.split("\n"): if not line:continue data_item_list = line.split(" ") # 跳过类别置信度小于0.5的 conf = float(data_item_list[5]) if(conf<0.5):continue # 单行txt转为xml中对应的obj obj_tmp = copy.deepcopy(obj_base) obj_tmp["name"] = class_name_list[int(data_item_list[0])] x_center = int(float(data_item_list[1])*img_width) y_center = int(float(data_item_list[2])*img_height) width = int(float(data_item_list[3])*img_width) height = int(float(data_item_list[4])*img_height) obj_tmp["bndbox"]["xmin"] = int(x_center-width/2.0) obj_tmp["bndbox"]["ymin"] = int(y_center-height/2.0) obj_tmp["bndbox"]["xmax"] = width + obj_tmp["bndbox"]["xmin"] obj_tmp["bndbox"]["ymax"] = height + obj_tmp["bndbox"]["ymin"] xml_tmp['annotation']['object'].append(obj_tmp) # 转为xml并写入对应文件 xmlstr = xmltodict.unparse(xml_tmp) xml = minidom.parseString(xmlstr) xml_pretty_str = xml.toprettyxml() with open(xml_path,"w") as f: f.write(xml_pretty_str) pbar.update(1) pbar.close()
2023年10月28日
38 阅读
0 评论
0 点赞
2023-10-25
[Github开源项目收集]:makephonedict 手机号字典生成器
Github项目地址:GitHub - asaotomo/makephonedict: 手机号字典生成器:可以根据用户需求定制化生成中国各大运营商和指定区域的手机号字典。工具简介: 可以根据用户需求定制化生成各大运营商和指定区域的手机号字典。使用方法: pyhton3 makepythondict.py使用提示: 运营商代码和区域代码,可在【手机号字典生成器-运营商代码和城市区域代码查询表.xlsx】中进行查看。运营商代码代码运营商4001移动4006联通4008电信区域代码北京 1101北京市天津 1201天津市河北 1301石家庄市1302唐山市1303秦皇岛市1304邯郸市1305邢台市1306保定市1307张家口市1308承德市1309沧州市1310廊坊市1311衡水市山西 1401太原市1402大同市1403阳泉市1404长治市1405晋城市1406朔州市1407晋中市1408运城市1409忻州市1410临汾市1411吕梁市内蒙古 1501呼和浩特市1502包头市1503乌海市1504赤峰市1505通辽市1506鄂尔多斯市1507呼伦贝尔市1508巴彦淖尔市1509乌兰察布市1522兴安盟1525锡林郭勒盟1529阿拉善盟辽宁 2101沈阳市2102大连市2103鞍山市2104抚顺市2105本溪市2106丹东市2107锦州市2108营口市2109阜新市2110辽阳市2111盘锦市2112铁岭市2113朝阳市2114葫芦岛市吉林 2201长春市2202吉林市2203四平市2204辽源市2205通化市2206白山市2207松原市2208白城市2224延边自治州黑龙江 2301哈尔滨市2302齐齐哈尔市2303鸡西市2304鹤岗市2305双鸭山市2306大庆市2307伊春市2308佳木斯市2309七台河市2310牡丹江市2311黑河市2312绥化市2327大兴安岭地区上海 3101上海市江苏 3201南京市3202无锡市3203徐州市3204常州市3205苏州市3206南通市3207连云港市3208淮安市3209盐城市3210扬州市3211镇江市3212泰州市3213宿迁市浙江 3301杭州市3302宁波市3303温州市3304嘉兴市3305湖州市3306绍兴市3307金华市3308衢州市3309舟山市3310台州市3311丽水市安徽 3401合肥市3402芜湖市3403蚌埠市3404淮南市3405马鞍山市3406淮北市3407铜陵市3408安庆市3410黄山市3411滁州市3412阜阳市3413宿州市3415六安市3416亳州市3417池州市3418宣城市福建 3501福州市3502厦门市3503莆田市3504三明市3505泉州市3506漳州市3507南平市3508龙岩市3509宁德市江西 3601南昌市3602景德镇市3603萍乡市3604九江市3605新余市3606鹰潭市3607赣州市3608吉安市3609宜春市3610抚州市3611上饶市山东 3701济南市3702青岛市3703淄博市3704枣庄市3705东营市3706烟台市3707潍坊市3708济宁市3709泰安市3710威海市3711日照市3713临沂市3714德州市3715聊城市3716滨州市3717菏泽市河南 4101郑州市4102开封市4103洛阳市4104平顶山市4105安阳市4106鹤壁市4107新乡市4108焦作市4109濮阳市4110许昌市4111漯河市4112三门峡市4113南阳市4114商丘市4115信阳市4116周口市4117驻马店市湖北 4201武汉市4202黄石市4203十堰市4205宜昌市4206襄阳市4207鄂州市4208荆门市4209孝感市4210荆州市4211黄冈市4212咸宁市4213随州市4228恩施自治州湖南 4301长沙市4302株洲市4303湘潭市4304衡阳市4305邵阳市4306岳阳市4307常德市4308张家界市4309益阳市4310郴州市4311永州市4312怀化市4313娄底市4331湘西自治州广东 4401广州市4402韶关市4403深圳市4404珠海市4405汕头市4406佛山市4407江门市4408湛江市4409茂名市4412肇庆市4413惠州市4414梅州市4415汕尾市4416河源市4417阳江市4418清远市4419东莞市4420中山市4451潮州市4452揭阳市4453云浮市广西 4501南宁市4502柳州市4503桂林市4504梧州市4505北海市4506防城港市4507钦州市4508贵港市4509玉林市4510百色市4511贺州市4512河池市4513来宾市4514崇左市海南 4601海口市重庆 5001重庆市四川 5101成都市5103自贡市5104攀枝花市5105泸州市5106德阳市5107绵阳市5108广元市5109遂宁市5110内江市5111乐山市5113南充市5114眉山市5115宜宾市5116广安市5117达州市5118雅安市5119巴中市5120资阳市5132阿坝自治州5133甘孜自治州5134凉山自治州贵州 5201贵阳市5202六盘水市5203遵义市5204安顺市5205毕节市5206铜仁市5223黔西南自治州5226黔东南自治州5227黔南自治州云南 5301昆明市5303曲靖市5304玉溪市5305保山市5306昭通市5307丽江市5308普洱市5309临沧市5323楚雄自治州5325红河自治州5326文山自治州5328西双版纳自治州5329大理自治州5331德宏自治州5333怒江自治州5334迪庆自治州西藏 5401拉萨市5425阿里地区陕西 6101西安市6102铜川市6103宝鸡市6104咸阳市6105渭南市6106延安市6107汉中市6108榆林市6109安康市6110商洛市甘肃 6201兰州市6202嘉峪关市6203金昌市6204白银市6205天水市6206武威市6207张掖市6208平凉市6209酒泉市6210庆阳市6211定西市6212陇南市6229临夏自治州6230甘南自治州青海 6301西宁市6323黄南自治州6325海南自治州6326果洛自治州6327玉树自治州6328海西自治州宁夏 6401银川市6402石嘴山市6403吴忠市6404固原市6405中卫市新疆 6501乌鲁木齐市6502克拉玛依市6523昌吉自治州6527博尔塔拉自治州6528巴音郭楞自治州6529阿克苏地区6530克孜勒苏柯尔克孜6531喀什地区6532和田地区6540伊犁自治州6542塔城地区6543阿勒泰地区免责声明: 本工具仅提供给安全测试人员进行安全自查使用 用户滥用造成的一切后果与作者无关 使用者请务必遵守当地法律 本程序不得用于商业用途,仅限学习交流
2023年10月25日
1,060 阅读
2 评论
0 点赞
2023-10-13
openEuler重置root密码(单用户模式)
重启系统在进入内核引导界面时按下键盘上的“e”键进入内核编辑界面在进入内核编辑界面后移动光标往下找到linux开头一行,在行的最后面输入:init=/bin/sh输入完成后,按快捷键:Ctrl+x 进入单用户模式,加载过程大概20秒,请耐心等待输入 mount -o remount,rw /,回车后输入 passwd ,然后输入两次新密码,如果输入第一次密码后提示密码复杂度不够,可忽略,直接再次输入,同样可以更改成功。然后输入 touch /.autorelabel 回车,输入 exec /sbin/init ,进入登录界面,注意:此时需重启系统后再用新设置的密码登陆。系统重启过程中,进入登录界面输入新设置的root密码,登录系统
2023年10月13日
604 阅读
0 评论
1 点赞
2023-10-12
Java Stream学习笔记
1.Stream介绍1.1 概述什么是Stream?java 8 新增的Stream配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。Stream对流的操作分类中间操作,每次返回一个新的流,可以有多个。(筛选filter、映射map、排序sorted、去重组合skip—limit)终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。(遍历foreach、匹配find–match、规约reduce、聚合max–min–count、收集collect)Stream特性stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。stream不会改变数据源,通常情况下会产生一个新的集合或一个值。stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。1.2 Stream与传统遍历对比几乎所有的集合(如 Collection 接口或 Map 接口等)都支持直接或间接的遍历操作。而当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。例如现有一个需求:将list集合中姓张的元素过滤到一个新的集合中,然后将过滤出来的姓张的元素中,再过滤出来长度为3的元素,存储到一个新的集合中传统遍历import java.util.ArrayList; import java.util.List; public class Demo1List { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("小昭"); list.add("殷离"); list.add("张三"); list.add("张三丰"); List<String> listA = new ArrayList<>(); for ( String s : list) { if (s.startsWith("张")) listA.add(s); } List<String> listB = new ArrayList<>(); for (String s: listA) { if (s.length() == 3) listB.add(s); } for (String s: listB) { System.out.println(s); } } }使用Stream写法import java.util.ArrayList; import java.util.List; public class Demo2Steam { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("小昭"); list.add("殷离"); list.add("张三"); list.add("张三丰"); list.stream() .filter(name -> name.startsWith("张")) .filter(name -> name.length() == 3) .forEach(name -> System.out.println(name)); } }2.Stream的创建2.0 顺序流和并行流stream和parallelStream的简单区分: stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:如果流中的数据量足够大,并行流可以加快处速度。除了直接创建并行流,还可以通过parallel()把顺序流转换成并行流2.1 通过 java.util.Collection.stream() 方法用集合创建流@Test public void testCreateStream(){ List<String> list = Arrays.asList("a", "b", "c"); // 创建一个顺序流 Stream<String> stream = list.stream(); System.out.println("创建顺序流:stream"); stream.forEach(x-> System.out.println(x)); // 创建一个并行流 Stream<String> parallelStream = list.parallelStream(); System.out.println("创建并行流:parallelStream"); parallelStream.forEach(x-> System.out.println(x)); }创建顺序流:stream a b c 创建并行流:parallelStream b c a2.2 使用java.util.Arrays.stream(T[] array)方法用数组创建流@Test public void testCreateStream(){ int[] array1={1,3,5,6,8}; IntStream stream1 = Arrays.stream(array1); stream1.forEach(x-> System.out.println(x)); String[] array2={"1","3","5","6","8"}; Stream<String> stream2 = Arrays.stream(array2); stream2.forEach(x-> System.out.println(x)); }2.3 使用Stream的静态方法:of()、iterate()、generate()@Test public void testCreateStream(){ Stream<Integer> stream1 = Stream.of(1, 2, 3); stream1.forEach(System.out::println); Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(3); stream2.forEach(System.out::println); Stream<Double> stream3 = Stream.generate(Math::random).limit(3); stream3.forEach(System.out::println); }3.Stream使用/Stream流的常用方法在使用stream之前,先理解一个概念:Optional 。Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。Stream流的常用方法分类:终结方法:返回值类型不再是Stream接口本身类型的方法,例如:forEach方法和count方法非终结方法/延迟方法:返回值类型仍然是Stream接口自身类型的方法,除了终结方法都是延迟方法。例如:filter,limit,skip,map,conat方法名称方法作用方法种类是否支持链式调用count统计个数终结方法否forEach逐一处理终结方法否filter过滤函数拼接是limit取用前几个函数拼接是skip跳过前几个函数拼接是map映射函数拼接是concat组合函数拼接是3.1 遍历/匹配(foreach、find、match)Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的@Test public void testStream(){ List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1); // 遍历输出符合条件的元素 list.stream().filter(x -> x > 6).forEach(System.out::println); // 匹配第一个 Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst(); // 匹配任意(适用于并行流) Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny(); // 是否包含符合特定条件的元素 boolean anyMatch = list.stream().anyMatch(x -> x > 6); System.out.println("匹配第一个值:" + findFirst.get()); System.out.println("匹配任意一个值:" + findAny.get()); System.out.println("是否存在大于6的值:" + anyMatch); }7 9 8 匹配第一个值:7 匹配任意一个值:8 是否存在大于6的值:true3.2 筛选(filter)@Test public void testStream(){ List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9); Stream<Integer> stream = list.stream(); stream.filter(x -> x > 7).forEach(System.out::println); }8 93.3 聚合(max、min、count)获取Integer集合中的最大/小值@Test public void testStream(){ List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6); // 自然排序 Optional<Integer> max = list.stream().max(Integer::compareTo); Optional<Integer> min = list.stream().min(Integer::compareTo); // 自定义排序 Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }); Optional<Integer> min2 = list.stream().min((o1, o2) -> o1.compareTo(o2)); System.out.println("自然排序的最大值:" + max.get()+",最小值:"+min.get()); System.out.println("自定义排序的最大值:" + max2.get()+",最小值:"+min2.get()); }自然排序的最大值:11,最小值:4 自定义排序的最大值:11,最小值:4获取String集合中最长/最低的元素@Test public void testStream(){ List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd"); Optional<String> max = list.stream().max(Comparator.comparing(String::length)); Optional<String> min = list.stream().min(Comparator.comparing(String::length)); System.out.println("最长的字符串:" + max.get()); System.out.println("最短的字符串:" + min.get()); }最长的字符串:weoujgsd 最短的字符串:pot获取员工工资最高的人@Data class Person { private String name; // 姓名 private int salary; // 薪资 private int age; // 年龄 private String sex; //性别 private String area; // 地区 } @Test public void testStream(){ List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 23, "male", "New York")); personList.add(new Person("Jack", 7000, 25, "male", "Washington")); personList.add(new Person("Lily", 7800, 21, "female", "Washington")); personList.add(new Person("Anni", 8200, 24, "female", "New York")); personList.add(new Person("Owen", 9500, 25, "male", "New York")); personList.add(new Person("Alisa", 7900, 26, "female", "New York")); Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getSalary)); Optional<Person> min = personList.stream().min(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return Integer.compare(o1.getSalary(), o2.getSalary()); } }); System.out.println("员工工资最大值:" + max.get().getSalary()); System.out.println("员工工资最小值:" + min.get().getSalary()); }员工工资最大值:9500 员工工资最小值:7000计算Integer集合中大于6的元素的个数@Test public void testStream(){ List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9); long count = list.stream().filter(x -> x > 6).count(); System.out.println("list中大于6的元素个数:" + count); }list中大于6的元素个数:43.4 映射(map、flatMap)映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。英文字符串数组的元素全部改为大写。整数数组每个元素+3@Test public void testStream(){ String[] strArr = { "abcd", "bcdd", "defde", "fTr" }; List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList()); List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11); List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList()); System.out.println("每个元素大写:" + strList); System.out.println("每个元素+3:" + intListNew); }每个元素大写:[ABCD, BCDD, DEFDE, FTR] 每个元素+3:[4, 6, 8, 10, 12, 14]将两个字符数组合并成一个新的字符数组@Test public void testStream(){ List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7"); List<String> listNew = list.stream().flatMap(s -> { // 将每个元素转换成一个stream String[] split = s.split(","); Stream<String> s2 = Arrays.stream(split); return s2; }).collect(Collectors.toList()); System.out.println("处理前的集合:" + list); System.out.println("处理后的集合:" + listNew); }处理前的集合:[m,k,l,a, 1,3,5,7] 处理后的集合:[m, k, l, a, 1, 3, 5, 7]3.5 规约(reduce)归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。@Test public void testStream(){ List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4); // 求和方式1 Optional<Integer> sum = list.stream().reduce((x, y) -> x + y); // 求和方式2 Optional<Integer> sum2 = list.stream().reduce(Integer::sum); // 求和方式3 Integer sum3 = list.stream().reduce(0, Integer::sum); // 求乘积 Optional<Integer> product = list.stream().reduce((x, y) -> x * y); // 求最大值方式1 Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y); // 求最大值写法2 Integer max2 = list.stream().reduce(1, Integer::max); System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3); System.out.println("list求积:" + product.get()); System.out.println("list求和:" + max.get() + "," + max2); }list求和:29,29,29 list求积:2112 list求和:11,113.6 收集(collect)collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。collect主要依赖java.util.stream.Collectors类内置的静态方法。3.6.1 归集(toList、toSet、toMap)因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。@Data class Person { private String name; // 姓名 private int salary; // 薪资 private int age; // 年龄 private String sex; //性别 private String area; // 地区 } @Test public void testStream(){ List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20); List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList()); Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet()); List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 23, "male", "New York")); personList.add(new Person("Jack", 7000, 25, "male", "Washington")); personList.add(new Person("Lily", 7800, 21, "female", "Washington")); personList.add(new Person("Anni", 8200, 24, "female", "New York")); Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000) .collect(Collectors.toMap(Person::getName, p -> p)); System.out.println("toList:" + listNew); System.out.println("toSet:" + set); System.out.println("toMap:" + map); }toList:[6, 4, 6, 6, 20] toSet:[4, 20, 6] toMap:{Tom=Person{name='Tom', salary=8900, age=23, sex='male', area='New York'}, Anni=Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}}3.7 排序(sorted)sorted,中间操作。有两种排序:sorted():自然排序,流中元素需实现Comparable接口sorted(Comparator com):Comparator排序器自定义排序员工按工资、年龄排序@Data class Person { private String name; // 姓名 private int salary; // 薪资 private int age; // 年龄 private String sex; //性别 private String area; // 地区 } @Test public void testStream(){ List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Sherry", 9000, 24, "female", "New York")); personList.add(new Person("Tom", 8900, 22, "male", "Washington")); personList.add(new Person("Jack", 9000, 25, "male", "Washington")); personList.add(new Person("Lily", 8800, 26, "male", "New York")); personList.add(new Person("Alisa", 9000, 26, "female", "New York")); // 按工资升序排序(自然排序) List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)) .map(Person::getName) .collect(Collectors.toList()); // 按工资倒序排序 List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()) .map(Person::getName) .collect(Collectors.toList()); // 先按工资再按年龄升序排序 List<String> newList3 = personList.stream() .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)) .map(Person::getName) .collect(Collectors.toList()); // 先按工资再按年龄自定义排序(降序) List<String> newList4 = personList.stream().sorted((p1, p2) -> { if (p1.getSalary() == p2.getSalary()) { return p2.getAge() - p1.getAge(); } else { return p2.getSalary() - p1.getSalary(); } }).map(Person::getName).collect(Collectors.toList()); System.out.println("按工资升序排序:" + newList); System.out.println("按工资降序排序:" + newList2); System.out.println("先按工资再按年龄升序排序:" + newList3); System.out.println("先按工资再按年龄自定义降序排序:" + newList4); }按工资升序排序:[Lily, Tom, Sherry, Jack, Alisa] 按工资降序排序:[Sherry, Jack, Alisa, Tom, Lily] 先按工资再按年龄升序排序:[Lily, Tom, Sherry, Jack, Alisa] 先按工资再按年龄自定义降序排序:[Alisa, Jack, Sherry, Tom, Lily]参考资料Java Stream流(详解)_java stream()-CSDN博客【java基础】吐血总结Stream流操作_java stream流操作-CSDN博客Java 8 Stream | 菜鸟教程 (runoob.com)
2023年10月12日
39 阅读
0 评论
0 点赞
1
2
3
4
...
24