【Java基础学习】Integer类剖析

【Java基础学习】Integer类剖析

一、Field

提示:斜体表示进制标识,并非数值中的一位

1. Integer.MAX_VALUE

public static final int MAX_VALUE = 0x7fffffff;

int在Java内存中占4个字节(32位),取值范围位 -231 ~ 231 - 1,因为总共32位,故可以表示 232 个数,一分为二,即 232 / 2,则正数和负数分别可以表示 231 个数,然而不包括0,因此需要从正数中拿一个给0腾位置,从而取正数最大值为 231 - 1。

十进制 231 对应的十六进制为 0x80000000,故十进制 231 - 1 对应的十六进制为 7fffffff

根据上述,int最大值对应的十六进制为0x7fffffff

2. Integer.MIN_VALUE

public static final int MIN_VALUE = 0x80000000;

在了解int最小值前,需要知道一点:负数在计算机中使用的是其数值的补码保存。

十进制 231 对应的二进制为 0100,0000,…,0000(…代表5组四个0)

231 补码计算过程:其二进制取反加一

0100,0000,…,0000 -> 01011,1111,…,1111 -> 0100,0000,…,0000

3. digits

final static char[] digits = {
  ‘0’ , ‘1’ , ‘2’ , ‘3’ , ‘4’ , ‘5’ ,
  ‘6’ , ‘7’ , ‘8’ , ‘9’ , ‘a’ , ‘b’ ,
  ‘c’ , ‘d’ , ‘e’ , ‘f’ , ‘g’ , ‘h’ ,
  ‘i’ , ‘j’ , ‘k’ , ‘l’ , ‘m’ , ‘n’ ,
  ‘o’ , ‘p’ , ‘q’ , ‘r’ , ‘s’ , ‘t’ ,
  ‘u’ , ‘v’ , ‘w’ , ‘x’ , ‘y’ , ‘z’
};

为方法中将整型转换为字符数组提供相应字符。

二、Method

1. public static String toString(int i, int radix)

功能: 将十进制的i转换为radix进制的字符串
参数:

  • 第一个参数:需要转换的整型
  • 第二个参数:转换的进制
public static String toString(int i, int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) //如果进制基数参数不在合适范围内(Character.MIN_RADIX~Character.MAX_RADIX,即2~36)
        radix = 10;

    /* Use the faster version */
    if (radix == 10) {  //十进制就直接使用另一个toString方法输出,一个参数的toString(int i)方法,是默认i为十进制。
        return toString(i);
    }

    /**
     * buf字符数组长度为33原因:
     * int型占32位,故最长长度是在使用二进制时,数值为临界值,要使用32个字符分别存储每一位。
     * 同时还需要一位用来存放符号,故此处字符数组长度设置为33。
     */
    char buf[] = new char[33];  //定义存储int转换后的结果。此处使用char数组,其长度为33。
    boolean negative = (i < 0);  //保存标识是否为负数
    int charPos = 32;  //从char数组最后一位开始

    if (!negative) {  //如果为负数,先将i变为其相反数,也就是正值
        i = -i;
    }

    while (i <= -radix) {  //循环将int每一位转换为字符存储在字符数组中,从低位开始
        buf[charPos--] = digits[-(i % radix)];  //此处直接使用Integer中存放进制单位数的常量数组
        i = i / radix;  //每获得一位,就除10
    }
    buf[charPos] = digits[-i];  

    if (negative) {  //如果为负数,将符号存放到字符数组中
        buf[--charPos] = '-';
    }

    return new String(buf, charPos, (33 - charPos));
}
Character.MAX_RADIX

总所周知,数字09有10个,字母az有26个,故共有36个,而十六进制中从10开始就是用字母从a开始表示直到f(代表15),因而假如使用所有数字和字母来表示某进制中的单位数,则最多可以表示到35,当然从0开始,故最大可表示36进制,Character.MAX_RADIX=36

Character.MIN_RADIX

一进制,只能表示一个数,不管它有多长,故一般不适用,因而最小用二进制,Character.MIN_RADIX=2

2. private static String toUnsignedString0(int val, int shift)

功能: 求十进制的整型val转换为shift所代指进制(shift并非直接表示进制,具体请看下述代码中的注释)存放的二进制后,从左至右首个1的左边0的个数
参数:

  • 第一个参数:十进制整型数
  • 第二个参数:偏移量,用以代指进制
private static String toUnsignedString0(int val, int shift) { //shift只能为1~5,1-二进制,2-四进制,3-八进制,4-十六进制
	int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);  //mag是val用二进制表示至少的位数
	int chars = Math.max(((mag + (shift - 1)) / shift), 1);  //(mag + (shift - 1)) / shift)是将二进制表示下的位数转换为其它进制表示的位数,后面1是保证位数至少为1,因为为0,后面字符数组就不可能保存val每个数字
	char[] buf = new char[chars];

	formatUnsignedInt(val, shift, buf, 0, chars);  //将val转换为shift代表的进制,并保存在buf字符数组中
	
	// Use special constructor which takes over "buf".
	return new String(buf, true);
}
Integer.numberOfLeadingZeros(val)

求val转为二进制,并使用32位存放时,从左至右第一个1前面的0个数。例如,8(10) 变为二进制 1000(10) ,共32位,第一个1在倒数第四位,故前面有28个0,故返回28。

3. static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len)

功能: 将整数val转换为对应进制,并保存在buf字符数组中

参数:

  • 第一个参数:要转换的十进制整数

  • 第二个参数: 偏移量,如果转换为二进制为1,八进制为3,十六进制为4

  • 第三个参数: 用于存储转换进之后保存的数组

  • 第四个参数: buf开始放入数据的开始位置的偏移量

  • 第五个参数: val二进制的长度

static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
        int charPos = len;
        int radix = 1 << shift;  //根据偏移量得到进制基数,假如shift=3,则1左移3为=位,得到8,此时表示八进制
        int mask = radix - 1;  //对应进制能使用的最大数码,八进制下为7
        do {
            //charPos先减1,是数组最后一个元素的下标,offset表示偏移量,一般为0表示不产生偏移,此处偏移相当于左移右移
            buf[offset + --charPos] = Integer.digits[val & mask]; //val与mask进行逻辑与,同时为1结果为1
            val >>>= shift;  //每进行一次循环,val无符号右移一位,以便一位位将数字将转换字符存到字符数组buf中
        } while (val != 0 && charPos > 0);

        return charPos;
    }

4. public static int parseInt(String s, int radix)

功能: 将字符串s转换为radix进制的整型
参数:

  • 第一个参数:需要转换的字符串
  • 第二个参数:转换的进制
public static int parseInt(String s, int radix) throws NumberFormatException {
    if (s == null) {
        throw new NumberFormatException("null");
    } else if (radix < 2) {  //Character.MIN_RADIX,与toString(int i, int radix)中类似
        throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
    } else if (radix > 36) {  //Character.MAX_RADIX
        throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
    } else {
        boolean negative = false;  //是否为负数,负数-true
        int i = 0;
        int len = s.length();
        int limit = -2147483647;  //int正数最大值为2147483647,但后面while循环每次转换int的一位数字是通过result -= digit,故而最后得到的是是负数,因而此处limit也为负值,便于后面进行范围判断
        if (len <= 0) {
            throw NumberFormatException.forInputString(s);
        } else {
            char firstChar = s.charAt(0);
            if (firstChar < '0') {  //小于字符0,说明第一个并未数字,可能为正负符号
                if (firstChar == '-') {
                    negative = true;
                    limit = -2147483648;  //int负数绝对值的最大值为2147483648,剩余与前面limit赋值同理
                } else if (firstChar != '+') {
                    throw NumberFormatException.forInputString(s);
                }

                if (len == 1) {
                    throw NumberFormatException.forInputString(s);
                }

                ++i;
            }
            //假设方法输入Integer.MIN_VALUE,即-2147483648,十进制
            int multmin = limit / radix;  //multmin = 214748364

            int result;
            int digit;
            for(result = 0; i < len; result -= digit) {  //循环到最后一个字符时,result=-214748364,进入循环
                digit = Character.digit(s.charAt(i++), radix);  //digit = 8
                //判断result是否小于multmin,此时正好等于,故不满足
                if (digit < 0 || result < multmin) {  //result *= radix;  result
                    throw NumberFormatException.forInputString(s);
                }
                
                //每循环一次,就乘上基数
				result *= radix;  //result = -214748364 * 10 = -2147483640
                if (result < limit + digit) {  //主要在于最后一次循环,判断是否小于int范围最小值或最大值的相反数加上最后一个字符代表的数值
                    throw NumberFormatException.forInputString(s);
                }
            }

            return negative ? result : -result;
        }
    }
}
细节剖析

【Java基础学习】Integer类剖析_第1张图片

multmin = limit / radix

可以从边界值进行考虑,在parseInt方法参数是s=“-2147483648”,radix=10,即要将字符串"-2147483648"转换为十进制int值。上述for循环进入到最后一次循环时,result = -214748364,最后一字符’8’对应数字8,要将最后一个字符加入到结果中,需要先让result * 10,也就是result * 基数。然而在乘10之前,可以通过判断此时result是否已经小于multmin,假如此时result为-214748365,这个乘10后就已经超出int范围,肯定是不合理的,因此可以在result * 基数前先进行result < multmin判断,故multmin = limit / radix(当然对于正数和负数其limit是不同的,因为int范围为-231 ~ 231 - 1,即-2147483648 ~ 2147483647)。如果满足result < multmin 且digit >= 0后,就对result 乘10。

result < limit + digit

可以看成result - digit < limit,就是在进行 result -= digit 前判断最终结果是否超除int范围

相关

欢迎在观看的各位留言,对于其中有误或不足的地方可以在评论区提出。觉得不错的可以点赞、收藏加关注,感谢各位!

你可能感兴趣的:(Java基础学习,java)