Apache工具包方法——Hex.encodeHexString(byte[] data)源码浅析

【2019-07-02 注:标题是Hex.encodeHexString(byte[] data) 的源码解析,但在实际测试过程中,改了方法名称,内部实现还是完全一样的。】

最近正在研究加密的相关方法和思想,有时候会用到byte类型的数组密钥或者密文,由于经常会遇到要将这鬼东西与数据库进行存取操作的情况,并且大多数情况都是将这样的byte数组转化为字符串进行存储的,因此用到了题目中的API,现对其源码实现进行总结和思考。

public static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', 
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };public static String byte2HexString(final byte[] data) {final int l = data.length;final char[] out = new char[l << 1];// two characters form the hex value.for (int i = 0, j = 0; i < l; i++) {out[j++] = DIGITS_UPPER[(0xF0 & data[i]) >>> 4];out[j++] = DIGITS_UPPER[0x0F & data[i]];}return new String(out);
}

源码中我们注意到了DIGITS_UPPER这个char[] 数组,事实上这个byte2HexString的实现原理是:将data中的每个byte元素拆分为两个十六进制数,作为DIGITS_UPPER数组的下标,然后找到其对应的char字符,组装成一个char[]数组。

测试用例

	public static void main(String[] args) {byte[] org = {1, 2, 3, 15, 10, 16, 17, 32, 0, 8};// 01 02 03 0F 0A 10 11 20 00 08String hexstr = DataConvertUtil.byte2HexString(org);System.out.println("转化结果:" + hexstr);}

执行结果:

转化结果:0102030F0A1011200008

 结果是完全没有问题的,下面是图解(20190702追加图解)

首先data.length获取到data数组的元素个数(数组长度也就是元素的个数),然后再初始化一个新的char数组,out = new char[l << 1];这里值得注意的是char数组的长度,源码中用移位运算来表示,事实上在我上一篇文章中已经写得很明确,将一个数左移一位等价于将这个数 ×2,也就是说这个char数组的长度是data数组的二倍!为什么?原因如下:data中的每个元素都是byte类型,每个元素8个bit,分为高四位低四位,而每四位就可以表示一个0x0到0x15的十六进制数字,因此我们想将data中的每个元素用两个十六进制的数字表示就必须初始化一个是data长度两倍的char数组,这就是out对象的长度是[l << 1]的原因。

我们在源码汇中也可以看到这样的注释// two characters form the hex value.

紧接着,for循环。我们可以在脑海中创建这样一幅景象,两个并列的数组byte[] data和char[] out我们从data中取第一个元素,将其以二进制的数字表示出来,然后拆分高四位低四位,分别找到对应的两个十六进制的字符表示,然后再塞入char[]数组中,这就是这个for循环的功能!

0xF0 & data[i]根据“与运算”的逻辑规则,我们得知其目的是为了使得data[i]的低四位都变成0;然后>>>4无符号右移4位,取得高四位所表示的数值,我们可以换一种理解,“与”的目的是让低四位变成0,然后右移是为了去掉高四位后面的四个0,这样我们就拿到了高四位表示的值(我们已经知道二进制的四位数的取值范围就是0到15)。然后将这个高四位表示的值作为index找到对应的DIGITS_LOWER数组中的字符,并赋值给out[j],然后++两次,代表高位一次和低位一次,这样,我们就成功的完成了一组高四位低四位的拆分、替换、重组,然后只要循环data数组的长度就可以对每个byte元素进行相同的拆分重组操作了。

最后返回char[] out 。

这是一个非常简单实用的byte[]数组转化为String的小方法,API的开发者巧妙的利用'0'到'f'这十六个字符“代表” 0 到 15这十六个十六进制数,然后将byte元素逐一拆分并重组成一个新的char[]数组。

以上是本人经过实践之后对源码的分析和理解,喜欢的朋友记得点赞哦,作为一个工作仅两年的小菜鸟来说诚然是不小的鼓励,如果同行的朋友有什么问题和建议,还请不吝赐教!

2019-07-02 追加更新

这里需要注意一个问题,即byte的取值范围问题,原来之前的知识有漏洞,忽视了下面这句代码的重要性:

out[j++] = DIGITS_UPPER[(0xF0 & data[i]) >>> 4];

这句代码的信息量很大,首先, >>> 是为了取byte元素的高四位,这个不难理解,但是为什么一定要先进行(0xF0 & data[i]) 运算?这个 & 运算是不是可有可无?

一开始我也认为是可有可无的,但实际上并不是!byte 变量的取值范围很小,是 [-128  ~  127],同样是 1000 0000,int类型所表示的是128, 而byte类型锁表示的数是 -128 ,因此,必须先将 byte 变量进行扩容转正,那么实现方法就是 & 0xF0,否则的话,如果 一个 byte类型的F0 ,表示的数代表 -16,再 >>> 4 的话,就会得到 -1 ,很明显不符合要求,因此& 0xF0 这句代码必不可少。

另外一个问题是 j++ ,++ 在后代表先取值,在加 1,那么out[j++] = DIGITS_UPPER[(0xF0 & data[i]) >>> 4]; 就相当于下面这句代码:

out[j] = DIGITS_UPPER[(0xF0 & data[i]) >>> 4];
j++;

 总之,千万别小看这些细节,搞不明白还真容易翻船!不得不佩服这些写底层API “轮子”的大神,能把各种语法和知识用到极致!

如果老铁们有幸看到这篇文章,而且也玩头条的话,欢迎关注我的头条号,不得不说,以前写博客是两三天一更,已经感觉很累,现在头条号要日更,还要篇篇精品,真的非常累,希望大家多多关注!头条号搜索 “Java圣斗士” ,谢谢老铁了!

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

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

相关文章

计算机考试400,400作文:电脑考试

400作文&#xff1a;电脑考试今天下午第三节课是大家最爱的电脑课&#xff0c;第三节课的上课铃还没敲响&#xff0c;大家就早早来到电脑室门口&#xff0c;拍好整齐的队伍&#xff0c;等待电脑金老师来带领我们进电脑室。终于&#xff0c;金老师面带微笑从办公室走到了我们这边…

史上最容易理解的暴力递归和动态规划~~

史上最容易理解的暴力递归和动态规划~~介绍递归和动态规划暴力递归&#xff1a;1&#xff0c; 把问题转化为规模缩小了的同类问题的子问题2&#xff0c; 有明确的不需要继续进行递归的条件(base case)3&#xff0c; 有当得到了子问题的结果之后的决策过程 4&#xff0c; 不记录…

英雄联盟与人生奋斗的类比讨论

自从去年毕业之后就已经很少玩英雄联盟了&#xff0c;最近半年更是一次都没碰过这个游戏了。 更新还是异常的频繁&#xff0c;打斗还是异常的激烈&#xff0c;比赛还是异常的水&#xff08;S系列中国队的表现&#xff09;。 我今天并不是想追忆曾经的激情&#xff0c;而是想把…

如何最好手机硬件测试软件,手机硬件出现故障?简单几部教你自己动手检测! _手机资讯...

很多人在使用手机时&#xff0c;经常遇到例如屏幕触摸不准、距离感应器不反应、手机按键失灵等类似问题&#xff0c;有的情况是系统故障&#xff0c;但大多数是属于硬件故障&#xff0c;那如何判定呢&#xff1f;其实很多安卓手机自带的有硬件检测工具&#xff0c;下面就以小米…

qq传输文件的软件测试点,超强新功能 QQ传文件夹测试版抢先试用

QQ传文件夹测试版试用(1)中关村在线软件事业部消息 腾讯体验中心今日(7月29日)发布了一个新的体验项目“QQ2009传文件夹测试版”。QQ的传文件功能&#xff0c;相信多数用户都使用过。在之前的版本中&#xff0c;很多用户反馈希望增加传文件夹的功能&#xff0c;方便多文件的传输…

黑色玫瑰服务器延迟高,LOL:含金量最高的服务器,黑色玫瑰垫底,最后一个钻石起步!...

原标题&#xff1a;LOL&#xff1a;含金量最高的服务器&#xff0c;黑色玫瑰垫底&#xff0c;最后一个钻石起步&#xff01;黑色玫瑰。它是英雄联盟中非常特别的一个大区。这个大区是中间位置&#xff0c;电十&#xff0c;却是比电二高手还要多的地方。因为这个大区小姐姐特别的…

Java网络编程————UDP实现ThinkPad S5网络唤醒

功能要求&#xff1a;通过Java程序实现ThinkPad S5 笔记本网络唤醒 必备知识&#xff1a; 一、定义&#xff1a;网络唤醒&#xff0c;通过局域网、互联网或通讯网络&#xff0c;以有线网卡的形式&#xff0c;向目标电脑发送魔法包(Magic Packet)&#xff0c;让电脑自动开机。…

奥特曼系列ol服务器名称带怪兽,《奥特曼系列ol》怪兽图鉴 怪兽阵容

《奥特曼系列ol》这款游戏中的怪兽图鉴也是很多玩家非常关注的问题之一哦&#xff0c;随着游戏的不断的更新&#xff0c;游戏也是加入了不少全新的玩法&#xff0c;一定让很多玩家觉得有些迷惑吧。下面小编为大家带来《奥特曼系列ol》怪兽图鉴以及怪兽阵容&#xff0c;希望大家…

继上一篇博客--javaweb通过接口来实现多个文件压缩和下载(包括单文件下载,多文件批量下载)

通过动态分配地址来提升javaweb文件下载接口的其兼容性和可扩展性&#xff1a; &#xff08;上篇博文地址&#xff1a;https://blog.csdn.net/weixin_37766296/article/details/80044000&#xff09;log4j.properties 文件&#xff1a; log4j.rootLogger debug,stdout,D,Elog4…

服务器主机启动不显示,服务器主机不启动怎么回事

服务器主机不启动怎么回事 内容精选换一换本文介绍了主机迁移服务SMS各特性版本的功能发布和对应的文档动态&#xff0c;新特性将在各个区域(Region)陆续发布&#xff0c;欢迎体验。源端服务器数据收集声明。源端服务器上安装和配置完迁移Agent后&#xff0c;迁移Agent会把源端…

最简明扼要的 Systemd 教程,只需十分钟

systemctl常用命令介绍~~~Systemctl是一个systemd工具&#xff0c;主要负责控制systemd系统和服务管理器。 Systemd是一个系统管理守护进程、工具和库的集合&#xff0c;用于取代System V初始进程。Systemd的功能是用于集中管理和配置类UNIX系统。启动及服务大多数主流发行版要…

Java常用设计模式————抽象工厂模式

简介 每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。 与工厂方法模式的区别 工厂方法模式针对的是一个产品等级结构&#xff0c;而抽象工厂模式针对的是多个产品等级结构&#xff0c;因此抽象工厂模式在结构上要比工厂方法模式更加复杂和抽象&#xff0c;也更…

CSS新手入门教程~~~~

CSS新手入门教程~~~~CSS简介&#xff1a;什么是 CSS? CSS 指层叠样式表 (Cascading Style Sheets)样式定义如何显示 HTML 元素样式通常存储在样式表中把样式添加到 HTML 4.0 中&#xff0c;是为了解决内容与表现分离的问题外部样式表可以极大提高工作效率外部样式表通常存储在…

Docker必备知识整理

Docker简介 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 Docker是用Go语言…

Exception和Error深入分析~~~

Exception和Error深入分析~~~Exception 和 Error 都是继承了 Throwable 类&#xff0c;在 Java 中只有 Throwable 类型的实例才可以被抛出&#xff08;throw&#xff09;或者捕获&#xff08;catch&#xff09;&#xff0c;它是异常处理机制的基本组成类型。 Exception 和 Erro…

Java常用设计模式————原型模式(二)之深拷贝与浅拷贝

引言 clone顾名思义就是复制&#xff0c; 在Java语言中&#xff0c; clone方法被对象调用&#xff0c;所以会复制对象。所谓的复制对象&#xff0c;首先要分配一个和源对象同样大小的空间&#xff0c;在这个空间中创建一个新的对象。那么在java语言中&#xff0c;有几种方式可…

Java面试宝典————基础篇

参考原文&#xff1a;《Java面试题全集&#xff08;上&#xff09;》 1.Java中的基本数据类型有哪些&#xff1f; 类型&#xff1a;byte short int long float double boolean char 字节&#xff1a;1 2 4 8 4 8 1 2 2.面向…

Git初学札记(零)————EGIT完成Eclipse到GitHub一条龙

eclipse安装Egit插件 首先我们要找到所需的egit插件的url更新地址。百度一大堆&#xff0c;但是我还是希望自己去寻找。 打开Eclipse Downloads官网&#xff0c;在页面底部直接输入“egit”关键字&#xff0c;并直接点击第一条搜索到的结果。然后点击Downloads标签页&#xff0…

Eclipse生成SSH传输密钥并实现GitHub的SSH代码提交

生成公私密钥 打开eclipse首选项完成如下操作&#xff1a;保存密钥&#xff1a;这里注意&#xff0c;博主之前已经生成过密钥了&#xff0c;因此这里只是演示截图&#xff0c;如果此时点击保存&#xff0c;会弹出“是否覆盖”提示框。 其中&#xff0c;id_rsa代表非对称加密算法…

SpringBoot————快速搭建springboot项目

完成项目的创建信息 浏览器打开SPRING INITIALIZR网址&#xff1a; http://start.spring.io/ 如下图所示完成配置&#xff1a; 1.完成基础项目配置 2.相关名称 3.依赖jar包&#xff0c;如果是web项目&#xff0c;那么这里选择的Web依赖已经包含了开发web项目所必须的服务器…