记一次二进制转换byte时出现的问题

问题:

想要进行二进制转换为byte

发现java的byte包装类Byte,提供了静态方法:parseByte(String s, int radix)

作用是将字符串s转化为byte类型,radix表示这个字符串数据是什么进制

正好符合要求

一个八位的二进制数,必然在-128(11111111)到127(01111111)之间,就是一个标准的byte类型数据

出现问题是因为我这里实际数据 10101000 转化中报如下错误

Exception in thread “main” java.lang.NumberFormatException: Value out of range. Value:“10101000” Radix:2

报错

数据超出范围

问题原因分析

于是去阅读了这段源码

    public static byte parseByte(String s, int radix)
        throws NumberFormatException {
        int i = Integer.parseInt(s, radix);
        if (i < MIN_VALUE || i > MAX_VALUE)
            throw new NumberFormatException(
                "Value out of range. Value:\"" + s + "\" Radix:" + radix);
        return (byte)i;
    }

发现先调用了int包装类Integer的parseInt(s, radix)方法,得到int,再强制类型转换为byte

类型转换前,判断了这个int值是否在-128到127之前,如果越界就会报这个错误

debug发现Integer的parseInt返回结果为168

显然,一定是parseInt没有将字符串当做带符号位的二进制数进行处理

阅读源码:

public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * WARNING: This method may be invoked early during VM initialization
         * before IntegerCache is initialized. Care must be taken to not use
         * the valueOf method.
         */

        if (s == null) {
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

        int result = 0;
        boolean negative = false;
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;
        int multmin;
        int digit;

        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            multmin = limit / radix;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }
                result -= digit;
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }

果然如此,简单一看,发现有这样的一段判断代码,我加上注释给大家看一下(只是解决这个问题的话,其他部分就不用看了)

//判断了首位字符如果不是数字
if (firstChar < '0') { // Possible leading "+" or "-"
    //判断了如果是减号(干了什么先不管)
    if (firstChar == '-') {
        negative = true;
        limit = Integer.MIN_VALUE;
    } 
    //如果不是减号,再判断了如果不是加号会抛出异常
    else if (firstChar != '+')
        throw NumberFormatException.forInputString(s);
	//走到这里说明是减号或加号中的一个,判断了字符串总长度,如果只有1,抛出异常,不能单独只有一个符号
    if (len == 1) // Cannot have lone "+" or "-"
        throw NumberFormatException.forInputString(s);
    i++;
}

说明parseInt方法,字符串首位可以带上±符号来表示正负

数字部分不会考虑符号位,是当做无符号数在转换

所以本应是符号数10101000(-40),实际处理成无符号数+10101000(168)

解决方案

1.第一种解决方案是,加上±号

自行将首位当做符号位判断,处理字符串首位0替换加号,1替换减号

这种方案下,表示二进制数的字符串,如果合规且长度不大于8,就百分百正确

但如果长度大于8位,还会抛出越界异常,这是正常的,因为确实越界

2.第二种解决方案是,先调用Integer的parseInt(s, radix)方法,转换为int,再将int强制类型转换为byte

这种方案,如果直接使用,其实会产生错误的结果 -88

因为强制类型转化的过程,是在操作二进制补码,最会相当于,会将传入的二进制字符串当做是补码操作,具体产生这个现象的原因,下面分析一下Java中int强制类型转换为byte的过程

    这个过程,是按照2进制位在操作

    首先我们知道计算机中保存数据就都是使用补码

    也知道int占用4个字节,共32位,其中一个符号位,所以可以表示-2^312^31-1的数据

    那么还用 10101000 举例,10101000经过parseInt后变成了168

    分析(byte)168的操作

	1.首先计算机直接就拿到32位的补码

		0 00000000 00000000 00000001 0101000

	2.再直接丢弃掉前24位

  	剩下 1 0101000

	3.将余下八位当做是byte类型的8位补码存入byte

	完成了

  校验一下

  补码为:1 0101000

  源码是:1 1011000

  转化十进制:

          1 1011000

        = - (2^6+2^4+2^3)

        = - (64+16+8)

        = - 88

所以这种方式,其实相当于原本传入的二进制字符串就是补码,才是正确的

那么就可以先自行将原码转换为补码,然后再执行这第二种方法的操作,就是正确结果了

同样也必须保证就八位,不越界,虽然这个方式越界了也不会报错,但如果越界,相当于是先转换成的int % 256之后,再进行强转,并没有什么意义

总结:两种方法应对八位二进制符号数存入byte都是完全可行的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 可以使用Java的位运算符将二进制的0和1转换byte数组。 例如,下面的代码将二进制字符串"01010101"转换成一个byte数组: ```java String binaryString = "01010101"; byte[] bytes = new byte[binaryString.length() / 8]; for (int i = 0; i < binaryString.length(); i += 8) { int j = i / 8; bytes[j] = (byte) Integer.parseInt(binaryString.substring(i, i + 8), 2); } ``` 这样每8个二进制位就被转化成了一个byte。也可以使用ByteBuffer类的put()方法或者 Bitwise等库的方法进行操作 ### 回答2: 0和1二进制转换byte数组的方法是将每8位二进制转换为一个字节。根据二进制数计算机内部表示的规则,一个字节可以存储8位二进制数。 假设我们有一个包含0和1的二进制字符串,长度为n。首先,我们需要确定原始二进制字符串的长度是否为8的倍数。如果不是,我们可以在字符串的前面补0,直到长度为8的倍数。 然后,将补齐后的二进制字符串按照每8位分割,并将每8位二进制转换为一个十进制数,即一个字节。 最后,将得到的所有字节存储在一个byte数组中。每个字节的值范围是0到255。 例如,对于二进制字符串"010100110110000101010001",长度为24,不是8的倍数。我们在前面补齐0,得到"00010100110100000101010001"。然后按照每8位分割,得到3个二进制数"00010100","11010000","101010001",将它们分别转换为十进制数20,208,161,然后存储在byte数组中,所以byte数组的值为{20, 208, 161}。 需要注意的是,byte数组是一种字节数组,而不是字符串数组。它用于在计算机中存储和传输二进制数据。 以上就是将0和1二进制转换byte数组的方法。 ### 回答3: 0和1二进制转换byte数组的方法如下: 首先需要确定byte数组的长度。由于一个byte数据类型占8个二进制位,所以将0和1的二进制数字符串长度除以8后,得到的结果就是byte数组的长度。 然后,将0和1的二进制数字符串每8位一组,转换成对应的十进制数。这里可以使用位运算符来实现,将每8位的二进制数通过左移和或运算,转换为对应的十进制数。 最后,将转换得到的十进制数逐个存入byte数组中。可以使用循环遍历的方式,将每个十进制数赋值给byte数组的相应索引位置。 最终得到的byte数组即为将0和1二进制字符串转换而来的结果。 下面是一个简单示例代码: ```java public class BinaryToByteArray { public static byte[] convertToByteArray(String binaryString) { int length = binaryString.length() / 8; byte[] byteArray = new byte[length]; for (int i = 0; i < length; i++) { String binaryByteString = binaryString.substring(i * 8, (i + 1) * 8); int decimalValue = Integer.parseInt(binaryByteString, 2); byteArray[i] = (byte) decimalValue; } return byteArray; } public static void main(String[] args) { String binaryString = "01100001"; // 示例二进制字符串 byte[] byteArray = convertToByteArray(binaryString); for (byte b : byteArray) { System.out.print(b + " "); } } } ``` 在上述示例中,输入的二进制字符串为"01100001",转换后得到的byte数组内容为97。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值