Java源码阅读——Integer

JDK版本

java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

不同的版本的实现可能会有些差异。

类定义

public final class Integer extends Number implements Comparable<Integer>
  1. 父类为Number,主要是一些类型转换的方法。
  2. 实现接口为Comparable,主要是Integer对象之间进行比较的方法。

属性

这里只列出了部分属性,其他属性在讲到具体方法时会列出。

//整型最小值
@Native public static final int   MIN_VALUE = 0x80000000;
//整型最大值
@Native public static final int   MAX_VALUE = 0x7fffffff;
//该包装类对应的基本类型
@SuppressWarnings("unchecked")
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
//digits数组为根据不同基数将整数转换为字符时,可能出现的数值。比如说16进制可能出现的字符为0~e。
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'
};
//DigitTens和DigitOnes为辅助数组,在getChars(int i, int index, char[] buf)方法中使用
final static char [] DigitTens = {
    '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
    '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
    '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
    '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
    '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
    '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
    '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
    '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
    '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
    '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
    } ;
final static char [] DigitOnes = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    } ;

toString相关方法

toString相关方法用于将给定整数转换为字符串。

toString(int i, int radix)方法

该方法根据基数radix,将整数i转换为字符串

public static String toString(int i, int radix) {
    /**
     * Character中保存着基数的范围,Character.MIN_RADIX=2,
     * Character.MAX_RADIX=36,在这个范围之外的基数是非法的,
     * 默认基数为10。
     */
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        radix = 10;
    //如果基数是10,直接采用Integer的toString(int i)方法进行转换
    if (radix == 10) {
        return toString(i);
    }
    /**
     *  Java中一个整型为4个字节,即32位,当基数为2时,能够转换得到最大
     * 的字符串11111111111111111111111111111111,再加上负数需要负号,
     * 故分配长度为33的字符数组用来临时存储转换得到的字符。
     */
    char buf[] = new char[33];
    //判断是否为负数
    boolean negative = (i < 0);
    //从末尾开始存放转换后得到的字符,数组从0开始,故从32开始存放
    int charPos = 32;
    /**
     * 如果不是负数,将其转换为负数进行处理。个人认为之所以要转换为负数,
     * 主要是为了统一进行处理,而无需分别对正负数进行处理。Java中整型的
     * 范围为-2147483648~2147483647。如果统一用正数进行处理,当i为最小值
     * -2147483648时,无对应的正数2147483648可进行操作。如果统一用负数进
     * 行处理,当i为最大值2147483647,有相应的负数-2147483647可进行操作。
     */
    if (!negative) {
        i = -i;
    }
    while (i <= -radix) {
        //根据取余得到的值从上述属性中的digits数组中获取字符
        buf[charPos--] = digits[-(i % radix)];
        i = i / radix;
    }
    buf[charPos] = digits[-i];
    //根据是否为负数加上负号
    if (negative) {
        buf[--charPos] = '-';
    }
    //获取起始位置和实际字符长度,由字符数组生成字符串
    return new String(buf, charPos, (33 - charPos));
}

toString(int i)方法

该方法根据给定的整数返回相应的字符串,默认基数为10。

public static String toString(int i) {
    //如果i是最小值,直接返回相应字符串,因为其无法进行之后的-i操作
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    /**
     * 使用Integer的stringSize(int x)获取i转换为字符串后的字符数,该
     * 方法要求传入的数为整数。对于负数来说,还需要负号这个字符,故需
     * 要stringSize(-i) + 1,获得实际字符数。
     */
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    /* 使用Integer的getChars(int i, int index, char[] buf)获取整数i转
     * 换为字符串的字符数组buf。
     */
    getChars(i, size, buf);
    return new String(buf, true);
}

stringSize(int x)方法

该方法用于获取整数i有多少位,要求整数i必须为非负数。比如输入10,将返回2;输入100,将返回3。

//sizeTable数组为辅助数组,用于辅助stringSize(int x)方法的实现
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };
/**
 * 根据给定的正整数x获取其位数,使用辅助数组sizeTable来完成操作。思路是从小
 * 到大与sizeTable进行比较。当x小于9时,肯定只有一位;否则与99相比,小于99的
 * 话,肯定只有两位,依次类推。
 */
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

getChars(int i, int index, char[] buf)方法

该方法将整数i的每一位转换为字符存放到字符数组buf中,index表示该整数将占用的字符数组长度。

//DigitTens和DigitOnes为辅助数组,用于辅助getChars(int i, int index, char[] buf)方法的实现
final static char [] DigitTens = {
    '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
    '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
    '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
    '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
    '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
    '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
    '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
    '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
    '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
    '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
    } ;
final static char [] DigitOnes = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    } ;
static void getChars(int i, int index, char[] buf) {
    int q, r;
    //charPos用来指示当前得到的字符的存放位置
    int charPos = index;
    //sign用于标记正负数
    char sign = 0;
    /**
     * 将整数i统一转换为正数进行处理,方便进行位操作。此时必须保证整数i
     * 不为最小值,以防溢出。
     */
    if (i < 0) {
        sign = '-';
        i = -i;
    }
    /** 
     * 当i大于等于65536时,每次获取i的最后两位存放到字符数组中,选用65536
     * 的原因见之后解释。
     */
    while (i >= 65536) {
        /** 
         * q保存除去最后两位后剩下的数值。这里之所以不用乘法加移位操作来替
         * 代除法操作,主要是因为一个较大的数进行乘法操作容易溢出。
         */
        q = i / 100;
        /**
         * 实际上是进行r = i - (q * 100)的操作。i每左移一位,等同于i乘二。
         * 故q<<6等同于q*2^6,即q*64。故(q << 6) + (q << 5) + (q << 2)等同于
         * q*64+q*32+q*4,即q*100。此时r保存i的最后两位。采用移位操作的原因是
         * 移位操作的效率比使用乘法的效率高。
         */
        r = i - ((q << 6) + (q << 5) + (q << 2));
        i = q;
        /**
         * 这里借助字符数组DigitOnes和字符数组DigitTens来获取这两位上的字符。
         * DigitOnes能根据r获取个位上的字符,DigitTens能根据r获取十位上的字符。
         */
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }
    //当i小于65536时,每次获取i的最后一位存放到字符数组中
    for (;;) {
        /** 
         * 实际上是进行r=i/10操作,即r=i*0.1的操作。i每无符号右移移位,等同于i
         * 除以2。故(i * 52429) >>> (16+3)等同于i*52429/2^19,即i*52429/524288,
         * 相当于r=i*0.1。采用乘法和移位操作等原因是移位操作的效率比使用乘法的
         * 效率高,使用乘法的效率又比使用除法的效率高。选用52429和16+3的原因见
         * 之后解释。
         */
        q = (i * 52429) >>> (16+3);
        // 实际上是进行r = i-(q*10)操作,解释同上,此时r保存i的最后一位。
        r = i - ((q << 3) + (q << 1));
        //借助字符数组digits根据r来获取字符。
        buf [--charPos] = digits [r];
        i = q;
        if (i == 0) break;
    }
    //判断是否需要添加负号
    if (sign != 0) {
        buf [--charPos] = sign;
    }
}

要使整数a和整数b进行a>>>b的操作结果最接近0.1,应该有 a = 2 b / 10 + 1
(1)当b取10时,有2^10=1024, 103/1024=0.1005859375。
(2)当b取11时,有2^11=2048, 205/2048=0.10009765625。
(3)当b取12时,有2^12=4096, 410/4096=0.10009765625。
可以看出,当b越大时,a越大,进行q=(i*a)>>>b操作时,为避免i*a操作溢出,a的 值也不是越大越好。我认为这里主要是从效率和精确度两个角度综合考虑,使用65536将其分为两部分操作:第一部分使用了除法,但一次性获取了两位;第二部分虽然一次只获取了一位, 但使用了乘法和位操作,从而避免了除法操作。

toHexString(int i)、toOctalString(int i)、toBinaryString(int i)

这三个方法的功能和实现类似,都是将整数i以16进制、8进制、2进制的字符串形式表示出来。

/** 
 * 返回一个整数参数的字符串表示形式在基数为16的无符号整数,使用Integer的
 * toUnsignedString0(int val, int shift)方法实现。
 */
public static String toHexString(int i) {
    return toUnsignedString0(i, 4);
}
/** 
 * 返回一个整数参数的字符串表示形式在基数为8的无符号整数,使用Integer的
 * toUnsignedString0(int val, int shift)方法实现。
 */
public static String toOctalString(int i) {
    return toUnsignedString0(i, 3);
}
/** 
 * 返回一个整数参数的字符串表示形式在基数为2的无符号整数,使用Integer的
 * toUnsignedString0(int val, int shift)方法实现。
 */
public static String toBinaryString(int i) {
    return toUnsignedString0(i, 1);
}

toUnsignedString0(int val, int shift)方法

该方法将给定的无符号整数val,根据shift,转换为相对应的字符串,使用Integer的formatUnsignedInt(int val, int shift, char[] buf, int offset, int len)实现。 shift参数就我个人理解,作用于radix相似。它指的是将二进制中的多少位作为一位,比如2进制则每1位作为一位,shift的值为1;8进制则每3位作为一位,shift的值为3;16进制则将每4位作为一位,shift的值为4。可以说,基数 r a d i x = 2 s h i f t

private static String toUnsignedString0(int val, int shift) {
    //计算给定的数的二进制表示形式的实际有效位数,numberOfLeadingZeros方法在后面会解释
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
    //计算给定的数根据shift进行转换后,实际所需要占用的字节数
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];
    //给定整数val,根据shift转换为字符数组
    formatUnsignedInt(val, shift, buf, 0, chars);
    return new String(buf, true);
}

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

该方法根据给定的整数val和shift,将其转换为字符串存放在字符数组buf中,offset为buf中开始存放的位置,len为需要存储的字符数。

 static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
    int charPos = len;
    int radix = 1 << shift;
    /** 
     * mask为掩码,表示将多少位作为1位。比如shift为3时,radix为8,相应的mask的值为7,
     * 其二进制形式为111,进行与操作可以得到3位。
     */
    int mask = radix - 1;
    do {
        /**
         * 通过val&mask每次可以得到val后三位所表示的数值,通过Integer的digits字符数组
         * 可以获取相应的数值所对应的字符。
         */
        buf[offset + --charPos] = Integer.digits[val & mask];
        //最低3位已转换为相应的字符,右移3位,继续进行转换
        val >>>= shift;
    } while (val != 0 && charPos > 0);
    return charPos;
}

parseInt相关方法

parseInt相关方法和toString相关方法相反,用于将给定的字符串转换为整数。

parseInt(String s, int radix)方法

该方法根据给定的字符串s和该字符串的基数radix,将其转换为相应的以10为基数的整数,该方法将忽略正号和前导零。

public static int parseInt(String s, int radix)
            throws NumberFormatException
{
    //字符串为null,抛出异常
    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;
    //i用于存放当前解析到的位置,该方法从字符的左端向右端进行处理
    int i = 0, len = s.length();
    /** 
     * 数值限制,由于统一转换为负数处理,故使用-Integer.MAX_VALUE用于限制
     * result所得到的值不能小于该值。
     */
    int limit = -Integer.MAX_VALUE;
    /** 
     * multmin也是一个限制,主要是用于判断该字符串进行转换后是否会溢出,具体
     * 解释见下面。
     */
    int multmin;
    int digit;
    if (len > 0) {
        char firstChar = s.charAt(0);
        //若小于字符0,则可能是正负号
        if (firstChar < '0') { 
            //若是负号,设置负数标准和限制数值
            if (firstChar == '-') {
                negative = true;
                //若为负数,设置限制为Integer.MIN_VALUE
                limit = Integer.MIN_VALUE;
            //若还不是正号,则只能是非法字符,抛出异常
            } else if (firstChar != '+')
                throw NumberFormatException.forInputString(s);
            //如果只有符号位,抛出异常
            if (len == 1) // Cannot have lone "+" or "-"
                throw NumberFormatException.forInputString(s);
            i++;
        }
        //设置multmin的值
        multmin = limit / radix;
        while (i < len) {
            //使用Charcter的digit方法获取当前字符在基数radix下所对应的数值
            digit = Character.digit(s.charAt(i++),radix);
            if (digit < 0) {
                //非法数值,即非法字符,抛出异常
                throw NumberFormatException.forInputString(s);
            }
            //使用小于进行比较,是因为统一使用了负数进行处理
            if (result < multmin) {
                /**
                 * 当result<multmin时,假设result=multmin-n,其中n为任意正整数,
                 * 那么当进行result *= radix操作时,相当于result=(multmin-n)*radix,
                 * 相当于result=(limit/radix-n)*radix,相当于result=limit-n*radix,
                 * 由于limit为限制的最小数值,故此时result的结果必然溢出。
                 */
                throw NumberFormatException.forInputString(s);
            }
            result *= radix;
            /**
             * 相当于result-digit<limit,注意是result-digit,因为统一使用了负数进行处理,
             * 由于limit为限制的最小数值,故此时result-digit的结果必然溢出。
             */
            if (result < limit + digit) {
                throw NumberFormatException.forInputString(s);
            }
            //统一使用负数处理,故使用减法
            result -= digit;
        }
    } else {
        //字符串长度为0直接抛出异常
        throw NumberFormatException.forInputString(s);
    }
    //根据负号标志判断是否要转换为正数
    return negative ? result : -result;
}

parseInt(String s)方法

该方法根据给定的字符串s,默认该字符串对应的基数为10,将其转换为相应的以10为基数的整数,该方法将忽略正号和前导零。使用Integer的parseInt(String s, int radix)方法实现。

public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s,10);
}

parseUnsignedInt(String s, int radix)方法

该方法类似于Integer的parseInt(String s, int radix)方法,但字符串s代表的为无符号数。注意Java中是没有无符号数的,该方法中大于整数最大值的字符串其实使用long类型来计算的, 然后再将其转换为int类型。Java中其实没有无符号数,这里所说的无符号数是相对的。通过使用负数来表示一部分的无符号数,此时负数的符号位视为有效数值,所以说是否为无符号数,主要在于使用者如何看待负数。比如说传入字符串2147483648,这是超过有符号整数范围,却在无符号整数范围内的数,输出结果为负数-2147483648。但从无符号数的角度看,将其二进制形式的符号位视为有效数值的话,-2147483648代表的就是无符号整数2147483648

public static int parseUnsignedInt(String s, int radix)
            throws NumberFormatException {
    if (s == null)  {
        //字符串为null,抛出异常
        throw new NumberFormatException("null");
    }
    int len = s.length();
    if (len > 0) {
        char firstChar = s.charAt(0);
        //若传入的字符串带有负号,抛出异常
        if (firstChar == '-') {
            throw new
                NumberFormatException(String.format("Illegal leading minus sign " +
                                                   "on unsigned string %s.", s));
        } else {
            if (len <= 5 || //整数最大值在最大基数下长度只有6,可以在有符号数的范围内处理
                (radix == 10 && len <= 9) ) { //整数最大值在十进制下长度只有10,可以在有符号数的范围内处理
                return parseInt(s, radix);
            } else {
                //超过有符号整数可以计算的范围,转换为Long类型进行处理
                long ell = Long.parseLong(s, radix);
                //判断转换后的数值是否在无符号整数的范围内,如果不在的话,高32位有非0数值,相与不为0
                if ((ell & 0xffff_ffff_0000_0000L) == 0) {
                    return (int) ell;
                } else {
                    //超过无符号整数的范围
                    throw new
                        NumberFormatException(String.format("String value %s exceeds " +
                                                            "range of unsigned int.", s));
                }
            }
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
}

parseUnsignedInt(String s)方法

该方法类似于Integer的parseInt(String s)方法,但字符串s代表的为无符号数,默认使用基数10。

public static int parseUnsignedInt(String s) throws NumberFormatException {
    return parseUnsignedInt(s, 10);
}

valueOf相关方法

valueOf相关方法类似parseInt相关方法,但parseInt相关方法得到的是整数基本类型,该方法得到的是整数的包装类。

IntegerCache缓存

valueOf相关方法的实现与IntegerCache相关。IntegerCache是Integer类中一个私有的静态类,用来为Integer提供缓存和重用,从而节省内存和提高性能。

private static class IntegerCache {
    //IntegerCache缓存的最小值
    static final int low = -128;
    //IntegerCache缓存的最大值
    static final int high;
    //缓存
    static final Integer cache[];
    static {
        //设置IntegerCache缓存的最大值
        int h = 127;
        //获取Java程序运行时设置的IntegerCache缓存的最大值
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                //若设置的IntegerCache缓存的最大值小于127,则仍然使用127
                i = Math.max(i, 127);
                /** 
                 * 数组的长度是有限制的,数组的length属性是int类型的,故数组的最大长度
                 * 为Integer.MAX_VALUE。而cache数组的长度是由low和high决定的,故high的
                 * 最大值只能是Integer.MAX_VALUE-(-low)-1。
                 */
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                //获取Java程序运行时设置的IntegerCache缓存的最大值无法解析则忽视
            }
        }
        high = h;
        //使用low和hight确定数组长度
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            //初始化数组,其中的值为low到hight范围之间的值
            cache[k] = new Integer(j++);
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

从中可以看出,默认情况下缓存0~127整数的包装类对象。

valueOf(int i)方法

该方法根据传入的整数i,获取其包装类型对象。

public static Integer valueOf(int i) {
    //假如整数i在IntegerCache缓存的范围内,直接返回缓存数组中的值
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

valueOf(String s, int radix)方法

该方法类似parseInt(String s, int radix)方法,但parseInt(String s, int radix)方法得到的是整数基本类型,该方法得到的是整数的包装类。使用Integer的 parseInt(String s, int radix)方法和valueOf(int i)方法实现。

public static Integer valueOf(String s, int radix) throws NumberFormatException {
    return Integer.valueOf(parseInt(s,radix));
}

valueOf(String s)方法

该方法类似parseInt(String s)方法,但parseInt(String s, int radix)方法得到的是整数基本类型,该方法得到的是整数的包装类。使用Integer的parseInt(String s, int radix)方法和valueOf(int i)方法实现。

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

属性和构造函数

//用于存放该整型包装类代表的整型基本类型数值
private final int value;

//传入整数进行构造
public Integer(int value) {
    this.value = value;
}

//传入字符串进行构建,使用Integer的parseInt(String s, int radix)方法实现
public Integer(String s) throws NumberFormatException {
    this.value = parseInt(s, 10);
}

Number父类中的方法

//重写Number父类中的方法,获取该对象代表的数值的byte类型数值
public byte byteValue() {
    return (byte)value;
}
//重写Number父类中的方法,获取该对象代表的数值的short类型数值
public short shortValue() {
    return (short)value;
}
//重写Number父类中的方法,获取该对象代表的数值的int类型数值
public int intValue() {
    return value;
}
//重写Number父类中的方法,获取该对象代表的数值的long类型数值
public long longValue() {
    return (long)value;
}
//重写Number父类中的方法,获取该对象代表的数值的float类型数值
public float floatValue() {
    return (float)value;
}
//重写Number父类中的方法,获取该对象代表的数值的double类型数值
public double doubleValue() {
    return (double)value;
}

Object祖先类中的方法

//重写toString()方法,获取该对象的字符串表示形式
public String toString() {
    return toString(value);
}
//重写hasCode()方法,使用Integer的hashCode(int value)实现
@Override
public int hashCode() {
    return Integer.hashCode(value);
}
//使用value变量表示其hasCode
public static int hashCode(int value) {
    return value;
}
//重写equals方法,先判断是否都为Integer类型,再判断两个对象的value值是否相同
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

getInteger相关方法

getInteger相关方法用于获取系统属性设置的整数。

decode(String nm)方法

该方法与getInteger相关方法的实现相关,用于解析给定的字符串,将其转换为相应的整数。
1. 使用0x、0X、#开头的字符串,将其视为十六进制数。
2. 使用0开头的字符串,将其视为八进制数。
3. 其他情况下,将其视为十进制数。

public static Integer decode(String nm) throws NumberFormatException {
    int radix = 10;
    int index = 0;
    boolean negative = false;
    Integer result;
    if (nm.length() == 0)
        throw new NumberFormatException("Zero length string");
    char firstChar = nm.charAt(0);
    //判断是否有符号位,并根据判断结果设置负数标志
    if (firstChar == '-') {
        negative = true;
        index++;
    } else if (firstChar == '+')
        index++;
    //判断是否为十六进制数
    if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
        index += 2;
        radix = 16;
    }
    //判断是否为十六进制数
    else if (nm.startsWith("#", index)) {
        index ++;
        radix = 16;
    }
    //判断是否为八进制数,由0开头且0不是最末尾字符
    else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
        index ++;
        radix = 8;
    }
    //在字符中间发现符号,抛出异常
    if (nm.startsWith("-", index) || nm.startsWith("+", index))
        throw new NumberFormatException("Sign character in wrong position");
    try {
        //使用Integer的valueOf(String s, int radix)方法获取相对应的整数,这里默认为正数
        result = Integer.valueOf(nm.substring(index), radix);
        //根据负号标志设置符号位
        result = negative ? Integer.valueOf(-result.intValue()) : result;
    } catch (NumberFormatException e) {
        /** 
         * 如何抛出异常,可能是由于前面使用正数进行了处理,整数最小值的绝对值超过了整数的
         * 最大值。将其转换为负数,再次尝试获取相对于的整数。
         */
        String constant = negative ? ("-" + nm.substring(index))
                                   : nm.substring(index);
        result = Integer.valueOf(constant, radix);
    }
    return result;
}

getInteger(String nm, Integer val)方法

该方法根据给定的字符串nm,获取相应的系统属性并转换为整数,若转换失败,则使用给定的整数val作为默认值。

public static Integer getInteger(String nm, Integer val) {
    String v = null;
    try {
        //获取系统属性
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    if (v != null) {
        try {
            //使用Integer的decode(String nm)进行解析
            return Integer.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    return val;
}

getInteger(String nm)方法

该方法根据给定的字符串nm,获取相应的系统属性并转换为整数,若转换失败,则返回null。使用Integer的getInteger(String nm, Integer val)实现。

public static Integer getInteger(String nm) {
    return getInteger(nm, null);
}

getInteger(String nm, int val)方法

该方法根据给定的字符串nm,获取相应的系统属性并转换为整数,若转换失败,则使用给定的整数val作为默认值。使用Integer的getInteger(String nm, Integer val)实现。

public static Integer getInteger(String nm, int val) {
    Integer result = getInteger(nm, null);
    return (result == null) ? Integer.valueOf(val) : result;
}

compareTo相关方法

compareTo相关方法用于比较两对象的大小。

compare(int x, int y)方法

该方法根据传入的两个整数判断其大小关系。x大于y,返回-1;x等于y,返回0; x小于y,返回1。

public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

compareTo(Integer anotherInteger)方法

该方法用于比较两个Integer对象的大小,使用Integer的compare(int x, int y)实现。

public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}

compareUnsigned(int x, int y)方法

Java中其实没有无符号数,这里所说的无符号数是相对的。其无符号数的最大 值其实是-1,其二进制的表示形式为11111111111111111111111111111111。负数的最高位为1,正数的最高位为0,从无符号数的角度看,负数的值一定大于正数。通过进行加MIN_VALUE的操作,可将负数的值进行正确的比较。

public static int compareUnsigned(int x, int y) {
    return compare(x + MIN_VALUE, y + MIN_VALUE);
}

属性

//整数类型表示的位数
@Native public static final int SIZE = 32;
//整数类型表示的字节数
public static final int BYTES = SIZE / Byte.SIZE;

无符号数相关方法

再次强调,Java中其实没有无符号数,这里所说的无符号数是相对的。通过使用负数来表示一部分的无符号数,此时负数的符号位视为有效数值,所以说是否为无符号数,主要在于使用者如何看待负数

toUnsignedString(int i, int radix)方法

该方法将无符号整数i,根据给定技术radix,转换为对应的字符串。

public static String toUnsignedString(int i, int radix) {
    return Long.toUnsignedString(toUnsignedLong(i), radix);
}

toUnsignedString(int i)方法

该方法给定整数i,将其转换为相应的无符号整数的字符串。该方法将整数i转换为long类型,在使用Long类型的toString方法将其转换为字符串。

public static String toUnsignedString(int i) {
    return Long.toString(toUnsignedLong(i));
}

toUnsignedLong(int x)方法

该方法给定整数x,将其转换为相应的无符号整数,使用long类型表示。对于正数来说,其对应的无符号数仍为其本身;对于负数在说,需要将其符号位看为有效数值。

public static long toUnsignedLong(int x) {
    //与0xffffffffL向与,保证高32位为0,在整数无符号数范围内
    return ((long) x) & 0xffffffffL;
}

divideUnsigned(int dividend, int divisor)方法

该方法获取两无符号整数的相除结果。

public static int divideUnsigned(int dividend, int divisor) {
    //使用Integer的toUnsignedLong(int x)方法转换为long类型再进行相除操作
    return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}

remainderUnsigned(int dividend, int divisor)方法

该方法获取两无符号整数的取余结果。

public static int remainderUnsigned(int dividend, int divisor) {
    //使用Integer的toUnsignedLong(int x)方法转换为long类型再进行取余操作
    return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}

位操作相关方法

highestOneBit(int i)方法

该方法是取整数i的二进制形式最左边的位为1且后面全部补零,最后返回int型的结果。
1. 对0来说,二进制形式中无1,故返回0。
2. 对负数来说,二进制形式中最左端,即第32位必为1,故返回值的二进制形式为10000000000000000000000000000000,即Integer.MIN_VALUE。
3. 对正数来说,比如3,其二进制形式00000000000000000000000000000011,故返回值的二进制形式为00000000000000000000000000000010,即2。

public static int highestOneBit(int i) {
    //将i与其带符号右移1位后的值相或,目的是为了将位为1的最高位的下一位也变为1,即连续2位为1
    i |= (i >>  1);
    //将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续4个1
    i |= (i >>  2);
    //将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续8个1
    i |= (i >>  4);
    //将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续16个1
    i |= (i >>  8);
    /** 
     * 将i与其带符号右移2位后的值相或,目的是使从位为1的最高位开始有连续32个1,此时位为1的最高
     * 为之后的位数都为1。
     */
    i |= (i >> 16);
    //i进行无符号右移移位,其实是将i位为1的最高位往右移移位,相减只剩下位为1的最高位
    return i - (i >>> 1);
}

以八位数00010100为例,第一次得到00011110,最后得到00011111,进行i - (i >>> 1),得到00010000。

lowestOneBit(int i)方法

该方法是取整数i的二进制形式最右边的位为1且前面全部补零,最后返回int型的结果。

public static int lowestOneBit(int i) {
    /**
     * 这里主要利用了补码的特性来实现这个操作。一个负数的补码为其除符号位
     * 的其他位数取反后加一。以8位为例,假设现在这个数为00001100,其负数的
     * 表示形式则为11110100,相与得到000000100。
     */
    return i & -i;
}

numberOfLeadingZeros(int i)方法

该方法返回给定整数的二进制形式的前导零的数目,该前导零将符号位计算在内。

public static int numberOfLeadingZeros(int i) {
    if (i == 0)
        return 32;
    int n = 1;
    /** 
     * 如果无符号右移16位得到0,说明高16位都为0,前导零数目加16,并将低16
     * 位移动到高16位上。
     */
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    /** 
     * 若前面的条件不满足,则说明高16位上存在非零位数,只需处理高16位即可;
     * 若前面的条件满足,则高16位上的前导零已处理完毕,并且已经将低16位移动
     * 到了高16位上,只需处理高16位即可。之后的处理与前面的处理一致,只是依
     * 次处理的位数为8位,4位,2位而已。
     */
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    /**
     * (1)若i为负数,则前面的四个条件都不满足,此时n为1,i>>>31为1,n-=i>>>31得n=0。
     *  即负数的前导零个数为0。
     * (2)若i为正数,在进行前面的四个条件判断和相关操作之后,还需要对最后两位进行判断。
     *  由于是正数,不可能两个都为0,要么都为1,要么前一位为0。将n初始化为1,默认最后两
     *  位中有0,使用i>>>31判断最后两位是否有零,有的话i>>>31的值为0;没有的话值为1,需
     *  要减去。比如00010000000000000000000000000000,其前导零个数有3个,上述四个条件只
     *  有最后一个条件满足,执行完后i的值为01000000000000000000000000000000,n的值为3。
     *  i>>>31的值为0,n-=i>>>31的值为3。
     */
    n -= i >>> 31;
    return n;
}

numberOfTrailingZeros(int i)方法

该方法与求前导零个数类似,不过与前导零从左向右求零的个数相反,该方法返回给定整数的二进制数从 右端开始计算零的个数,直到遇到非零位的零的个数。

public static int numberOfTrailingZeros(int i) {
    //y变量用于辅助计算
    int y;
    if (i == 0) return 32;
    int n = 31;
    y = i <<16; if (y != 0) { n = n -16; i = y; }
    y = i << 8; if (y != 0) { n = n - 8; i = y; }
    y = i << 4; if (y != 0) { n = n - 4; i = y; }
    y = i << 2; if (y != 0) { n = n - 2; i = y; }
    return n - ((i << 1) >>> 31);
}

bitCount(int i)方法

该方法用于计算给定的整数i的二进制形式中位为1的个数。

public static int bitCount(int i) {
    /**
     * 先总结一个规律,对于两位的二进制数来说,计算其位为1的个数有:
     * (1)二进制数00,有00-00=00,位为1的个数为0。
     * (2)二进制数01,有01-00=01,位为1的个数为1。
     * (3)二进制数10,有10-01=01,位为1的个数为1。
     * (4)二进制数11,有11-01=10,位为1的个数为2。
     * 总结,对于二进制数i,其位为1的个数n有规律:n=i-i>>>1。 
     */
    /**
     * 0x55555555的二进制表示形式为01010101010101010101010101010101。
     * 这里实际上的用了上述规律,把i的每两位当成一个个体来计算。可将i
     * 视为16个两位的独立的二进制数bi(0≤i≤15)。
     * i>>>1直接运用了上述规律。观察以上规律可以发现,i>>>1时其实是在高位
     * 补零,但由于这16个二进制数之间存在有位置关系,假设有b1b0,那么当进
     * 行i>>>1操作时,b1的低位将移动到b0的高位,这时无法保证在b0的高位进行
     * 补零的操作。因而将i>>>1与0x55555555进行与操作,可以将bi(0≤i≤15)的
     * 高位强制置为零。这时,将bi(0≤i≤15)的值相加就是i的二进制形式中位为
     * 1的个数。之后要做的就是不断地把bi(0≤i≤15)相加。
     */
    i = i - ((i >>> 1) & 0x55555555);
    /**
     * 0x55555555的二进制表示形式为00110011001100110011001100110011。这里实际
     * 做是将相邻的两个bi(0≤i≤15)相加。i&0x33333333实际上是保留bi(i=2k)所
     * 在的值,将bi(i=2k+1)置为0。(i>>>2)&0x33333333实际上是将bi(i=2k+1)移
     * 动到bi(i=2k)的位置上,再进行相加操作,从而实现部分bi(0≤i≤15)之间的
     * 相加。注意,相加之后bi不再只是代表两位,而是代表四位,因为两个两位的
     * bi(0≤i≤15)相加之后得到的值代表的是四位上为1的个数,故此时应该把i的每
     * 四位当成一个个体来计算。可将i视为8个四位的独立的二进制数bi(0≤i≤7)。
     */
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    //之后的三步相加操作和上面的相加操作类似。只不过bi的位数分别变为了4,8,16。
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    /**
     * 最后之所以与0x3f相与,是应为前面的两步并没有进行与操作,所以前面的数据是
     * 无效的。而整数i最多只有32位,使用后面6位就足够表示了。
     */
    return i & 0x3f;
}

rotateLeft(int i, int distance)方法

该方法将给定整数i左旋distance位。

public static int rotateLeft(int i, int distance) {
    return (i << distance) | (i >>> -distance);
}

rotateRight(int i, int distance)方法

该方法将给定整数i右旋distance位。

public static int rotateRight(int i, int distance) {
    return (i >>> distance) | (i << -distance);
}

signum(int i)方法

该方法返回给定整数的符号位,正数为1,零为0,负数为-1。

public static int signum(int i) {
    return (i >> 31) | (-i >>> 31);
}

reverse(int i)方法

该方法给定整数i,将其二进制形式反转得到新的整数。

public static int reverse(int i) {
    /**
     * 以八位为例,表示为ABCDEFGH,其做法为:
     * (1)每一位视为一个个体,每两位为一组进行反转,得到BADCFEHG
     * (2)每两位视为一个个体,每四位为一组进行反转,得到DCBAHGFE
     * (3)每四位视为一个个体,每八位为一组进行反转,得到HGFEDCBA
     * 32位整数依次类推。
     */
    i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
    i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
    i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
    /**
     * 到这里为止,每八位之间的反转已经完成,使用字母代表八位的话,
     * 现在该整数看做ABCD,接下来的操作就是将其反转为DCBA。
     * (1)i<<24实际上就是将D移动到A的位置,得到D000(每个0代表8个0)。
     * (2)i&0xff00实际上是得到00C0,左移8位,将C移动到B的位置,得到0C00。
     * (3)i>>>8实际上是将B移动到C的位置,得到0ABC,再和0xff00进行相与,得到00B0。
     * (4)i>>>24实际上就是将A移动到D的位置,得到000A。
     * (5)将上述四步得到的四个值进行相与,即可得到DCBA。
     */
    i = (i << 24) | ((i & 0xff00) << 8) |
        ((i >>> 8) & 0xff00) | (i >>> 24);
    return i;
}

reverseBytes(int i)方法

该方法给定整数i,以字节为单位进行反转,其实现与Integer类的reverse(int i)方法 中的最后一步类似。

public static int reverseBytes(int i) {
    return ((i >>> 24)           ) |
           ((i >>   8) &   0xFF00) |
           ((i <<   8) & 0xFF0000) |
           ((i << 24));
}

其他方法

sum(int a, int b)方法

该方法返回两个整数的和。

public static int sum(int a, int b) {
    return a + b;
}

max(int a, int b)方法

该方法使用Math类的max方法返回两个整数的最大值

public static int max(int a, int b) {
    return Math.max(a, b);
}

min(int a, int b)方法

该方法使用Math类的min方法返回两个整数的最小值。

public static int min(int a, int b) {
    return Math.min(a, b);
}

猜你喜欢

转载自blog.csdn.net/YINLINNEVERG/article/details/80918788