1.关于八股文:用最有效率的方法计算 2 乘以 8
答案:2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)
我:2X8最快的运算方式是2左移3位,那3X8最快的运算方式也是3左移3位吗?
GPT回答:是的,对于正整数来说,乘以2的n次方等价于将该数左移n位。因此,对于任何正整数m,m乘以8(即m * 8)最快的运算方式是将m左移3位(即m << 3)。因此,3乘以8的最快运算方式也是将3左移3位,即3 << 3。
2.之前的业务中有哪里是用到了位移运算?
搜索了一下自己的项目里,业务中的处理直接用到了位移运算的好像没有看到,倒是在一些工具类中看到了位移运算的使用。
(1)进制的转换,用于对图片数据等的处理:
#16进制字符串转字节数组
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
首先,图片数据在网络传输的过程中一般以16进制字符串来表示,因为这样:更容易在网络上传输。这种方式可以绕过二进制数据可能引发的编码问题,确保数据的可靠传输。(也有缺点:
数据膨胀: 十六进制字符串表示的数据通常比原始二进制数据更大,因为每个字节都需要两个字符来表示。这会增加网络传输的数据量和传输时间。
效率低下: 将图片转换为十六进制字符串需要额外的计算,而且在服务端需要再次将其转换回二进制数据。这增加了数据处理的复杂性和成本,并可能影响系统的性能。
存储空间: 存储十六进制字符串表示的图片需要更多的存储空间,因为它们通常比原始二进制数据更大。
但是,将图片上传到服务器或者在客户端进行存储或使用,一般是要转换为对应的字节数组的。
这段代码定义了一个
hexStringToBytes
方法,它将一个十六进制的字符串转换成一个字节数组。这个转换过程涉及将十六进制数(通常用两个字符表示,如1A
表示一个字节)转换成对应的字节值。下面是这个方法的逐步分析:参数
String hexString
:输入的十六进制字符串。方法流程
参数校验:
- 检查输入字符串是否为
null
或空字符串。如果是,方法立即返回null
。这一步确保了后续操作有有效的输入字符串。字符串预处理:
- 将输入的十六进制字符串转换为大写形式,这样做是为了统一处理字符,因为十六进制数中的
A
到F
可以是大写或小写,但实际值是相同的。计算目标字节数组长度:
- 由于每两个十六进制字符表示一个字节,方法通过将字符串长度除以2来计算结果字节数组的长度。
初始化变量:
- 将十六进制字符串转换成字符数组
hexChars
,方便逐个字符处理。- 初始化目标字节数组
d
,其长度为上一步计算出的长度。转换逻辑:
- 遍历每对十六进制字符,每次循环处理两个字符(一对),将它们转换为一个字节:
int pos = i * 2;
计算当前处理对的起始位置。- 使用
charToByte(hexChars[pos])
将第一个字符转换为字节值,并左移4位(转换为高4位)。- 使用
charToByte(hexChars[pos + 1])
将第二个字符转换为字节值(低4位)。- 使用位或操作
|
合并这两个值形成完整的字节,并将结果存储在字节数组d[i]
中。返回结果:
- 方法最后返回填充好的字节数组
d
。注意事项
- 这段代码引用了
charToByte
方法,该方法的实现没有在代码段中给出。通常,这个方法应该能够将十六进制字符(0
-9
和A
-F
)转换为相应的字节值(0
到15
)(应该就是以8位的0或1来表示这些数)。- 输入字符串应只包含有效的十六进制字符(
0
-9
,A
-F
或a
-f
),且长度应为偶数,以确保每个字节都能由两个字符表示。如果输入字符串不符合这些条件,方法的行为可能不符合预期。这个方法提供了一种常见的将十六进制字符串转换为字节数组的实现方式,广泛用于数据编码、加密算法和网络通信等领域。
像这个方法中,对进制的处理就用到了左移4位,比如说这里有一个字符串“1A2F”来表示一个16进制数,那么我们通过charToByte这个方法,会将"1"转为0000 0001,将“A”转为0000 1010,“2”转为“0000 0010”,“F”转为“0000 1111”,又因为每两个十六进制字符表示一个字节,所以“1”和“A”要放在一个byte里,“2”和“F”放在一个byte里,那么就需要把0000 0001进行左移4位,变为0001 0000,然后再和0000 1010 进行"|"或运算,就合并为:0001 1010,存放在Byte[]数组中。(后面的数同理)
#二进制字符串转换十六进制字符串
public static String binaryString2hexString(String bString)
{
if (bString == null || bString.equals("") || bString.length() % 8 != 0)
return null;
StringBuffer tmp = new StringBuffer();
int iTmp = 0;
for (int i = 0; i < bString.length(); i += 4)
{
iTmp = 0;
for (int j = 0; j < 4; j++)
{
iTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1);
}
tmp.append(Integer.toHexString(iTmp));
}
return tmp.toString();
}
(2)加密算法工具类中,结果往往要以十六进制字符串的形式来表示,能够提高数据的可读性、传输性和兼容性,使得加密结果更易于处理和使用。
/**
* 使用SHA1算法对字符串进行加密
*
* @param str
* @return
*/
public static String sha1Encrypt(String str) {
if (str == null || str.length() == 0) {
return null;
}
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes(StandardCharsets.UTF_8));
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
#对于每个字节,将其高四位和低四位分别转换为对应的十六进制字符
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
byte0 >>> 4 & 0xf
是一个位运算操作,用于从一个字节中获取其高四位(即字节的前四位)。让我来解释这个表达式的含义:
byte0 >>> 4
:这是一个无符号右移操作符,将byte0
中的所有位向右移动4位。在移位过程中,右边多出的位会被丢弃,左边补0。这样操作后,byte0
的低四位会被移到高四位的位置。
& 0xf
:这是一个按位与操作符,用于与0xf
(即十进制的15)进行按位与运算。0xf
的二进制表示为00001111
,它的作用是将结果的高四位清零,保留低四位。综合起来,
byte0 >>> 4 & 0xf
的目的是从byte0
中获取其高四位,并将其存储在结果中,确保其他位都被清零。这样的操作通常用于将一个字节(8位)分成两个部分,分别处理高四位和低四位。