Java中对字节的详解
郝伟 2021/06/04

1 简介

在信息安全领域,对字节的操作非常频繁,所以本文对字节操作的相关内容进行详细介绍。

2 基本定义

1字节等于8个位,是计算机中数据的最基础的组成单元。在Java中,没有无符号数,所以1个字节的表示范围是 -128 ~ 127

3 初始化

二进制有初始化有三种方法:

注意:使用任何超出字节值域(即-128~127)的赋值都会会报 java.lang.Error: cannot convert from int to byte 错误。

4 常用运算

4.1 四则运算

节点变量支持常规的四则运算,但是需要注意一点就是返回的数据类型都是 Integer 所以需要进行转换。

先看这样的一个示例,以下代码实现两个字节的四则运算:

	public static void test1() {
		byte a = 0x7f;
		byte b = 0x3;

		var c1 = a + b;
		var c2 = a - b;
		var c3 = a * b;
		var c4 = a / b;

		System.out.println("c1 = " + c1 + ", " + getClassName(c1));
		System.out.println("c2 = " + c2 + ", " + getClassName(c2));
		System.out.println("c3 = " + c3 + ", " + getClassName(c3));
		System.out.println("c4 = " + c4 + ", " + getClassName(c4));
	}

  	public static String getClassName(Object o) {
		return o.getClass().getSimpleName();
	}

输出结果为:

c1 = 130, Integer
c2 = 124, Integer
c3 = 381, Integer
c4 = 42, Integer

由此可见,字节运算的底层实现是将字节型转为整型,再进行运算,然后返回一个整型。这样在理解上就比较容易,对结果也好评估。

4.2 特殊运算

4.2.1 或运算

或运算是最基本的逻辑运算之一,可以实现字节中每个位与位的运算,请看以下示例:

	public static void test3() {
		System.out.println("或运算");
		System.out.println(0b0 | 0b0);
		System.out.println(0b1 | 0b0);
		System.out.println(0b1 | 0b1);
		System.out.println(0b01010101 | 0b10101010);
	}

输出结果如下,输出分别是由低到高取得每一位的值,结果与预期一致。

或运算
0
1
1
255

4.2.2 或运算

与运算是最基本的逻辑运算之一,可以实现字节中每个位与位的运算,请看以下示例:

public static void test2() {
  System.out.println("变量与常量异或");
  byte b = (byte) 0b11111111;	
  System.out.println(b & 0b00000001);
  System.out.println(b & 0b00000010);
  System.out.println(b & 0b00000100);
  System.out.println(b & 0b00001000);
  System.out.println(b & 0b00010000);
  System.out.println(b & 0b00100000);
  System.out.println(b & 0b01000000);
  System.out.println(b & 0b10000000);
}

输出结果如下,输出分别是由低到高取得每一位的值,结果与预期一致。

变量与常量异或
1
2
4
8
16
32
64
128

4.2.3 非运算

与运算是最基本的逻辑运算之一,可以实现字节中每个位与位的运算,请看以下示例:

	
	public static void test4() {
		System.out.println("非运算");
		byte b1 = (byte) 0b00000000;
		byte b2 = (byte) 0b11111111;
		byte b3 = (byte) 0b01010101;

		System.out.println(byteToString(b1) + " --取反--> " + byteToString((byte)~b1));
		System.out.println(byteToString(b2) + " --取反--> " + byteToString((byte)~b2));
		System.out.println(byteToString(b3) + " --取反--> " + byteToString((byte)~b3));
	}

输出结果如下,输出分别是由低到高取得每一位的值,结果与预期一致。

非运算
00000000 --取反--> 11111111
11111111 --取反--> 00000000
01010101 --取反--> 10101010

4.2.4 异或运算

异或顾名思义,两个位不相同时为1,相同时为0,请看下面的示例。

	public static void test5() {
		System.out.println("异或运算");
		byte b1 = (byte) 0b00000000;
		byte b2 = (byte) 0b11111111;
		byte b3 = (byte) 0b01010101;

		xor(b1, b2);
		xor(b2, b3);
		xor(b3, b1);
	}
	
	public static void xor(byte b1, byte b2) {
		var bstr1 = byteToString(b1);
		var bstr2 = byteToString(b2);
		var bstr3 = byteToString((byte)(b1^b2));
		System.out.printf("%s ^ %s --> %s\n", bstr1, bstr2, bstr3);
	}

输出结果为:

异或运算
00000000 & 11111111 --> 11111111
11111111 & 01010101 --> 10101010
01010101 & 00000000 --> 01010101

实际上,与异或相对应的还是同或运行,即相同时为1,不同时为0,但是在Java中没有实现。我们可以对异或取反即可。

5 附录

5.1 几个引用到的函数

	public static String byteToString(byte b) {
		int datalen = 8;
		String[] data = new String[datalen];
		for (int i = 0, w = 1; i < datalen; i++, w *= 2) 
			data[datalen - i - 1] = (b & w) > 0 ? "1" : "0";		
		return String.join("", data);
	}

	public static String intToString(int b) {
		int datalen = 32;
		String[] data = new String[datalen];
		for (int i = 0, w = 1; i < datalen; i++, w *= 2) 
			data[datalen - i - 1] = (b & w) > 0 ? "1" : "0";		
		return String.join("", data);
	}

5.2 所有源代码

public class ByteOperationDemo {

	public static void main(String[] args) {
		test0();
		test1();
		test2();
		test3();
		test4();
		test5();
	}
	
	public static void test5() {
		System.out.println("异或运算");
		byte b1 = (byte) 0b00000000;
		byte b2 = (byte) 0b11111111;
		byte b3 = (byte) 0b01010101;

		xor(b1, b2);
		xor(b2, b3);
		xor(b3, b1);
		
	}
	
	public static void xor(byte b1, byte b2) {
		var bstr1 = byteToString(b1);
		var bstr2 = byteToString(b2);
		var bstr3 = byteToString((byte)(b1^b2));
		System.out.printf("%s ^ %s --> %s\n", bstr1, bstr2, bstr3);
	}
	
	
	public static void test4() {
		System.out.println("非运算");
		byte b1 = (byte) 0b00000000;
		byte b2 = (byte) 0b11111111;
		byte b3 = (byte) 0b01010101;

		System.out.println(byteToString(b1) + " --取反--> " + byteToString((byte)~b1));
		System.out.println(byteToString(b2) + " --取反--> " + byteToString((byte)~b2));
		System.out.println(byteToString(b3) + " --取反--> " + byteToString((byte)~b3));
	}
	
	public static void test3() {
		System.out.println("或运算");
		System.out.println(0b0 | 0b0);
		System.out.println(0b1 | 0b0);
		System.out.println(0b1 | 0b1);
		System.out.println(0b01010101 | 0b10101010);
	}
	
	public static void test2() {
		System.out.println("变量与常量异或");
		byte b = (byte) 0b11111111;	
		System.out.println(b & 0b00000001);
		System.out.println(b & 0b00000010);
		System.out.println(b & 0b00000100);
		System.out.println(b & 0b00001000);
		System.out.println(b & 0b00010000);
		System.out.println(b & 0b00100000);
		System.out.println(b & 0b01000000);
		System.out.println(b & 0b10000000);
	}
	
	public static void test1() {
		byte a = 0x7f;
		byte b = 0x3;

		var c1 = a + b;
		var c2 = a - b;
		var c3 = a * b;
		var c4 = a / b;

		System.out.println("c1 = " + c1 + ", " + getClassName(c1));
		System.out.println("c2 = " + c2 + ", " + getClassName(c2));
		System.out.println("c3 = " + c3 + ", " + getClassName(c3));
		System.out.println("c4 = " + c4 + ", " + getClassName(c4));
	}
	
	public static void test0() {
		for (int i = 0; i < 256; i++)
			System.out.println((i & 0xff) + ": " + byteToString((byte) i));
	}
	
	public static String getClassName(Object o) {
		return o.getClass().getSimpleName();
	}

 
	
	public static void showType(Object o) {
		//System.out.println(o instanceof Integer);
		//System.out.println(o.getClass().getName());
		System.out.println(o.getClass().getSimpleName());
	}

	public static String byteToString(byte b) {
		int datalen = 8;
		String[] data = new String[datalen];
		for (int i = 0, w = 1; i < datalen; i++, w *= 2) 
			data[datalen - i - 1] = (b & w) > 0 ? "1" : "0";		
		return String.join("", data);
	}

	public static String intToString(int b) {
		int datalen = 32;
		String[] data = new String[datalen];
		for (int i = 0, w = 1; i < datalen; i++, w *= 2) 
			data[datalen - i - 1] = (b & w) > 0 ? "1" : "0";		
		return String.join("", data);
	}
	
}