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

1. 1 简介

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

2. 2 基本定义

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

3. 3 初始化

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

  • 十进制数直接赋值,如 byte b = 100;
  • 使用十六进制表示, 如 byte b = 0xff;
  • 使用二进制表示, 如 byte b = 0b10001000; 所以在进行字节操作的时候就就会有这样的问题。

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

4. 4 常用运算

4.1. 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 特殊运算

4.2.1. 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. 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. 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. 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 附录

5.1. 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. 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);
    }

}

results matching ""

    No results matching ""