JDK源码之Integer类 & Long类分析

一 简介

Integer是int基本类型的包装类,同样继承了Number类,实现了Comparable接口,String类中的一些转化方法就使用了Integer类中的一些API,且fianl修饰不可继承:

 public final class Integer extends Number implements Comparable<Integer> {

Number传送门
Long类源码和Integer类源力基本相同,大部分API是一样的逻辑!

二 源码解析

Integer类API比较多也比较重要,分开几个部分解析:

1 属性

        // 包装类的int类型值
        private final int value;

        //两个被废弃的构造器,官方推荐valueOf形式
        @Deprecated(since="9")
        public Integer(int value) {
            this.value = value;
        }

        @Deprecated(since="9")
        public Integer(String s) throws NumberFormatException {
            this.value = parseInt(s, 10);
        }

        // int最小值,
        @Native public static final int   MIN_VALUE = 0x80000000;

        //int最大值,  int 范围 - 2^{31} 到2^{31}-1之间的整数即: -2147483648 ~2147483647
        @Native public static final int   MAX_VALUE = 0x7fffffff;

        // 表示二进制补码形式的int值的比特数比,32
        @Native public static final int SIZE = 32;

        //字节数常量,4
        public static final int BYTES = SIZE / Byte.SIZE;

        // Class类实例
        public static final Class<java.lang.Integer>  TYPE = (Class<java.lang.Integer>) Class.getPrimitiveClass("int");

        //将数字表示为字符串的所有可能字符,因为int支持从2进制到36进制,所以这里需要有36个字符才能表示所有不同进制的数字
        static final 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两个数组主要用于获取0到99之间某个数的十位和个位字符,
         * 比如48,通过DigitTens数组直接取出来十位为4,而通过DigitOnes数组取出来个位为8
         */
        static final byte[] 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',
        } ;
        static final byte[] 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',
        } ;

        /**
         * sizeTable数组主要用在判断一个int型数字(只能判断正数)对应字符串的长度。比如相关的方法如下,这种方法可以高效得到对应字符串长度,避免了使用除法或求余等操作
         * jdk8中并没有使用这个数组,直接用的while循环计算,正负数都可以判断,返回长度算上了符号长度,即-1的长度是2
         * static int stringSize(int x) {
         *       for (int i=0; ; i++)
         *           if (x <= sizeTable[i])
         *               return i+1; //直接通过判断返回长度
         * }
         */
        static final int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                99999999, 999999999, java.lang.Integer.MAX_VALUE };

2 toString方法(重点,需要用到上面三个byte矩阵数组)

       //实例方法
       public String toString() {
            return toString(value);
        }

        /**
         * 返回第一个参数的字符串形式,第二个参数为进制的基数,二进制10进制十六进制等
         */
        public static String toString(int i, int radix) {
            //如果基数小于2或者大于36,则默认使用10进制转换
            if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
                radix = 10;
            //返回int类型参数十进制形式字符串
            if (radix == 10) {
                return toString(i);
            }
            if (COMPACT_STRINGS) {
                byte[] buf = new byte[33];
                boolean negative = (i < 0);
                int charPos = 32; //从数组最后一位开始添加
                if (!negative) {
                    i = -i;
                }
                /**
                 * 按进制处理,求余digits从获取对应字符串,比如 -15转为16进制  -15 % 16 = 15 ,digits 中15 为 f
                 */
                while (i <= -radix) {
                    buf[charPos--] = (byte)digits[-(i % radix)];
                    i = i / radix;
                }
                buf[charPos] = (byte)digits[-i];
                if (negative) {
                    buf[--charPos] = '-';
                }
                return StringLatin1.newString(buf, charPos, (33 - charPos));
            }
            return toStringUTF16(i, radix);
        }

        /**
         * 返回int类型参数十进制形式字符串
         */
        public static String toString(int i) {
            int size = stringSize(i);
            if (COMPACT_STRINGS) { //jvm是否开启字符串压缩
                byte[] buf = new byte[size];
                getChars(i, size, buf); //将int参数字符串放入byte数组中
                return new String(buf, LATIN1);
            } else {
                byte[] buf = new byte[size * 2];
                StringUTF16.getChars(i, size, buf);// 思路与上面getChars一样,放进数组的时候会进行高低位两个byte放
                return new String(buf, UTF16);
            }
        }

        //返回给定int值的字符串表示长度
        static int stringSize(int x) {
            int d = 1;
            if (x >= 0) {
                d = 0;
                x = -x; //整数改为负数,统一用负数判断大小
            }
            int p = -10;//判断大小基数,大于-10,一位,否则再判断大于-100,两位等
            for (int i = 1; i < 10; i++) { // 判断9次
                if (x > p)
                    return i + d;
                p = 10 * p;
            }
            return 10 + d; //超过九位数,返回int最大的长度,10或者11位
        }

        //将int参数字符串放入byte数组中
        static int getChars(int i, int index, byte[] buf) {
            int q, r;
            int charPos = index; //数组开始位置坐标,传入的是数组大小,从 --index 最后一位往前添加数据
            boolean negative = i < 0;
            if (!negative) { //正数转化为负数
                i = -i;
            }
            /**
             * 每次取后两位数,将最后两位字符添加到数组中,比如: -2358
             * q=-23    整数相除,结果都为整数
             * r=-2300-(-2358)=58
             * 从DigitOnes和DigitTens中找出第58个字符,即8和5依次加入数组中
             */
            while (i <= -100) {
                q = i / 100;
                r = (q * 100) - i;
                i = q; // 每次增大100,即去掉后两位数,继续循环处理,直到成为两位数以内
                buf[--charPos] = DigitOnes[r];
                buf[--charPos] = DigitTens[r];
            }
            // 处理剩余的两位数,比如: -23     q=-2, r= 3
            q = i / 10;
            r = (q * 10) - i;
            buf[--charPos] = (byte)('0' + r); // 转换为byte存储

            if (q < 0) {
                buf[--charPos] = (byte)('0' - q);
            }
            //处理符号位
            if (negative) {
                buf[--charPos] = (byte)'-';
            }
            return charPos;
        }

        //按照一个字符占用两个byte处理
        private static String toStringUTF16(int i, int radix) {
            byte[] buf = new byte[33 * 2];
            boolean negative = (i < 0);
            int charPos = 32;
            if (!negative) {
                i = -i;
            }
            //按进制处理,求余digits从获取对应字符串,比如 -15转为16进制  -15 % 16 = 15 ,digits 中15 为 f
            while (i <= -radix) {
                StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);
                i = i / radix;
            }
            StringUTF16.putChar(buf, charPos, digits[-i]);
            if (negative) {
                StringUTF16.putChar(buf, --charPos, '-');
            }
            return StringUTF16.newString(buf, charPos, (33 - charPos));
        }

3 to系列其他方法

    //1.8新增方法,返回无符号参数int的十进制字符串,注意: 两个新增方法实现逻辑都在Long类中,Unsigned方法参数如果是有符号的(即负数),结果都会有问题
    public static String toUnsignedString(int i) {
        return Long.toString(toUnsignedLong(i));
    }

    /**
     * 将无符号int转换为long类型,负数不报错结果不正确
     * @since 1.8
     */
    public static long toUnsignedLong(int x) { return ((long) x) & 0xffffffffL; }

    //1.8新增方法: 根据进制基数,返回无符号int参数号的字符串形式,新增方法,功能与下面三种方法一样,只不过还支持10进制等进制
    public static String toUnsignedString(int i, int radix) {
        return Long.toUnsignedString(toUnsignedLong(i), radix);
    }

    // 转换为16进制字符串
    public static String toHexString(int i) {
        return toUnsignedString0(i, 4);
    }
    // 转换为8进制字符串
    public static String toOctalString(int i) {
        return toUnsignedString0(i, 3);
    }
    // 转换为2进制字符串
    public static String toBinaryString(int i) {
        return toUnsignedString0(i, 1);
    }

    // 将无符号整数转换为String,私有方法,只支持2,8,16三种进制转换, 负数不报错但结果不正确
    private static String toUnsignedString0(int val, int shift) {
        /**
         * 32减去numberOfLeadingZeros, 表示实际表示此数字只需要的位数。
         * 比如10的二进制补码是0000 0000 0000 0000 0000 0000 0000 1010,
         * 它实际只需要1010这4位数字就可以代表10. 所以10的mag就是4
         */
        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
        /**
         * 表示转换成byte数组所需要的长度,
         * 其中shift的值1-二进制,3-八进制,4-十六进制。比
         * 如10的mag是4,如果要转成二进制shift=1,则chars=4,因为需要长度为4的字符数组来存放1010。
         * 如果要转成16进制a,则shift=4,得出chars=1,因为只需要长度为1的字符串数组来存放结果a.
         */
        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
        if (COMPACT_STRINGS) {
            byte[] buf = new byte[chars];
            //将int值转化为对应进制的字符形式添加到buf数组中
            formatUnsignedInt(val, shift, buf, 0, chars);
            return new String(buf, LATIN1);
        } else {
            byte[] buf = new byte[chars * 2];
            formatUnsignedIntUTF16(val, shift, buf, 0, chars);
            return new String(buf, UTF16);
        }
    }

    /**
     获取int值补码形式前面的0的个数,0返回32,负数返回0
     该方法返回i的二进制从头开始有多少个0。i为0的话则有32个0。
     这里处理其实是体现了二分查找思想的,先看高16位是否为0,是的话则至少有16个0,否则左移16位继续往下判断,
     接着右移24位看是不是为0,是的话则至少有16+8=24个0,直到最后得到结果。
    */
    public static int numberOfLeadingZeros(int i) {
        if (i <= 0)
            return i == 0 ? 32 : 0;
        int n = 31;
        // 从最大数开始判断,依次将大数减小
        if (i >= 1 << 16) { n -= 16; i >>>= 16; }
        if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
        if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
        if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
        return n - (i >>> 1);// 返回二进制补码前面0的个数
    }

    //将int值转化为对应进制的字符形式添加到buf数组中
    static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
        /**
         * 二进制,因为2的1次方是2,所以shift就是1,那么radix就是1左移1位得到2,mask就是1,对应的二进制就是1;
         * 八进制,因为2的3次方是8,所以shift就是3,那么radix就是1左移3位得到8,mask就是7,对应的二进制就是111;
         * 十六进制,因为2的4次方是16,所以shift就是4,那么radix就是1左移4位得到16,mask就是15,对应的二进制就是1111;
         */
        int charPos = offset + len;
        int radix = 1 << shift;
        int mask = radix - 1; //掩码
        /**
         * 十进制数如果是转换成八进制或十六进制这种进制数为2的整数次方的进制,有更快的算法,就是先得到二进制,然后每几位一组转换。
         * 比如要把19转换成八进制:
         *   先把19转成二进制,也就是10011;
         *   因为8是2的3次方,所以把10011从低位开始每3位一组划分,也就是10 011;
         *   把10 011按每一组转为八进制,也就是2 3,所以19的八进制表示就是23。
         *
         * 循环val & mask 与运算的过程就像分组转换的过程,每次循环可以将mask对应的位数得到,再利用digits数组转换成对应的字符,这个字符就是这次分组的这几位所对应的结果,
         * 每次分组得到结果以后把val右移相应的位数,继续下一轮的循环分组。
         *
         * 比如val为19,shift为3,radix为8,mask为7。
         * 第一次循环:19 & 7 就是10011 & 111,结果为11,也就是3,通过digits数组得到这一位字符为3。然后10011右移3位,得到val为10。
         * 第二次循环:10 & 111,结果为10,也就是2,通过digits数组得到这一位字符为2。然后10右移3位,得到val为0,循环结束。
         * 最终结果就是23。
         */
        do {
            buf[--charPos] = (byte) Integer.digits[val & mask]; //分组转化算法思想
            val >>>= shift;
        } while (charPos > offset);
    }
    //使用两个byte存储字符形式添加
    private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
        int charPos = offset + len;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
            val >>>= shift;
        } while (charPos > offset);
    }

4 parse系列方法

        //解析十进制的字符串形式数字并返回int值
        public static int parseInt(String s) throws NumberFormatException {
            return parseInt(s,10);
        }

        /**
         * 将对应进制的字符串形式转化为十进制int返回,
         * 比如: Integer.parseInt("10",16)   =   16
         */
        public static int parseInt(String s, int radix)
                throws NumberFormatException
        {
            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"); }

            boolean negative = false;//是否为负数
            int i = 0, len = s.length();
            int limit = -Integer.MAX_VALUE;// 最小值

            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++;
                }
                int multmin = limit / radix;
                int result = 0;
                while (i < len) {//循环计算每一位值
                    //根据Character类获取当前对应字符对应进制的数字
                    int digit = Character.digit(s.charAt(i++), radix);
                    if (digit < 0 || result < multmin) {
                        throw NumberFormatException.forInputString(s);
                    }
                    result *= radix;  //乘进制数转换为十进制数结果
                    if (result < limit + digit) {
                        throw NumberFormatException.forInputString(s);
                    }
                    result -= digit;
                }
                return negative ? result : -result;
            } else {
                throw NumberFormatException.forInputString(s);
            }
        }

        /**
         * @since 1.8 将无符号的十进制字符串形式解析为int, 负数字符串形式会直接抛异常
         */
        public static int parseUnsignedInt(String s) throws NumberFormatException {
            return parseUnsignedInt(s, 10);
        }

        /**
         * @since 1.8 将对应进制的无符号字符串解析为int. 注意: "-10" 这种负数字符串形式会直接抛异常
         */
        public static int parseUnsignedInt(String s, int radix)
                throws NumberFormatException {
            if (s == 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 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
                            (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
                        return parseInt(s, radix); //调用parseInt方法
                    } else {
                        long ell = Long.parseLong(s, radix);
                        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);
            }
        }

        /**
         * 将对应进制的无符号CharSequence解析为int. 注意: "-10" 这种负数字符串形式会直接抛异常
         * 即可以使用StringBuffer等参数,逻辑与上面String参数是一样的
         * @since  9
         */
        public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)
                throws NumberFormatException {
            s = Objects.requireNonNull(s);

            if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
                throw new IndexOutOfBoundsException();
            }
            int start = beginIndex, len = endIndex - beginIndex;

            if (len > 0) {
                char firstChar = s.charAt(start);
                if (firstChar == '-') {
                    throw new
                            NumberFormatException(String.format("Illegal leading minus sign " +
                            "on unsigned string %s.", s));
                } else {
                    if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
                            (radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits
                        return parseInt(s, start, start + len, radix);
                    } else {
                        long ell = Long.parseLong(s, start, start + len, radix);
                        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 new NumberFormatException("");
            }
        }

        /**
         * 解析CharSequence为int,根据指定起始位置和进制数,即可以使用StringBuffer等参数,逻辑与上面String参数是一样的
         * @since  9
         */
        public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
                throws NumberFormatException {
            s = Objects.requireNonNull(s);

            if (beginIndex < 0 || beginIndex > endIndex || endIndex > s.length()) {
                throw new IndexOutOfBoundsException();
            }
            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");
            }

            boolean negative = false;
            int i = beginIndex;
            int limit = -Integer.MAX_VALUE;

            if (i < endIndex) {
                char firstChar = s.charAt(i);
                if (firstChar < '0') { // Possible leading "+" or "-"
                    if (firstChar == '-') {
                        negative = true;
                        limit = java.lang.Integer.MIN_VALUE;
                    } else if (firstChar != '+') {
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                    i++;
                    if (i == endIndex) { // Cannot have lone "+" or "-"
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                }
                int multmin = limit / radix;
                int result = 0;
                while (i < endIndex) {
                    // Accumulating negatively avoids surprises near MAX_VALUE
                    int digit = Character.digit(s.charAt(i), radix);
                    if (digit < 0 || result < multmin) {
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                    result *= radix;
                    if (result < limit + digit) {
                        throw NumberFormatException.forCharSequence(s, beginIndex,
                                endIndex, i);
                    }
                    i++;
                    result -= digit;
                }
                return negative ? result : -result;
            } else {
                throw NumberFormatException.forInputString("");
            }
        }

5 valueOf系列方法与静态内部缓存类

        /**
         * 静态内部类: 把-128~最大边界(默认是127)的数字缓存起来了,用于提升性能和节省内存
         * 最大边界可以通过-XX:AutoBoxCacheMax进行配置
         */
        private static class IntegerCache {
            static final int low = -128;
            static final int high;
            static final Integer cache[];//缓存数据

            static {
                // high value may be configured by property
                int h = 127;
                String integerCacheHighPropValue =
                        VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                if (integerCacheHighPropValue != null) {
                    try {
                        int i = parseInt(integerCacheHighPropValue);
                        i = Math.max(i, 127);
                        // Maximum array size is Integer.MAX_VALUE
                        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                    } catch( NumberFormatException nfe) {
                        // If the property cannot be parsed into an int, ignore it.
                    }
                }
                high = h;

                cache = new Integer[(high - low) + 1];
                int j = low;
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);//往数组中提前加入创建好的对象

                // range [-128, 127] must be interned (JLS7 5.1.7)
                assert Integer.IntegerCache.high >= 127;
            }
            //构造器私有,保护数据
            private IntegerCache() {}
        }

        // 根据int返回Integer对象
        public static Integer valueOf(int i) {
            //如果在-128-high缓存区间内,则返回缓存里的对象,即区间内用valueOf返回的对象都是同一个,相等的
            if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
                return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
            return new Integer(i);
        }

        // 根据字符串和进制基数构造Integer对象并返回
        public static Integer valueOf(String s, int radix) throws NumberFormatException {
            return Integer.valueOf(parseInt(s,radix));
        }

        // 根据String返回十进制Integer对象
        public static Integer valueOf(String s) throws NumberFormatException {
            return Integer.valueOf(parseInt(s, 10));
        }

7 getInteger和比较,hashCode等方法

       //Integer hash值是其value
        @Override
        public int hashCode() {
            return Integer.hashCode(value);
        }

        public static int hashCode(int value) {
            return value;
        }

        //比较value的int值是否相等,如果两个Integer的值应该用这个方法,而不是 ==
        public boolean equals(Object obj) {
            if (obj instanceof Integer) {
                return value == ((Integer)obj).intValue();
            }
            return false;
        }

        /**
         * Integer.getInteger(String)方法假设String参数是一个系统属性数值的名称,会读取该系统属性,
         * 然后把系统属性的值转换成一个数字。当我们调用Integer.getInteger("521") 应该是得到 null(系统默认肯定没有521的系统属性)。
         *
         * 常见的系统属性
         *   在JDK文档中System类中有这样的方法getProperties()在此方法的详细介绍中有下面的参数可供使用:
         *   java.version  Java 运行时环境版本
         *   java.vendor  Java 运行时环境供应商
         *   java.vendor.url  Java 供应商的 URL
         *   java.home  Java 安装目录
         *   当启动JVM时,请使用System.setProperty或使用-Dname = value标志
         */
        public static Integer getInteger(String nm) {
            return getInteger(nm, null);
        }

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

        public static Integer getInteger(String nm, Integer val) {
            String v = null;
            try {
                v = System.getProperty(nm);
            } catch (IllegalArgumentException | NullPointerException e) {
            }
            if (v != null) {
                try {
                    return Integer.decode(v);
                } catch (NumberFormatException e) {
                }
            }
            return val;
        }

    /**
     * ecode合适用来分析数字
     * 可以分析
     * 8进:010=>分析后为 8
     * 10进:10=>分析后为 10
     * 16进:#10|0X10|0x10=>分析后是 16
     * 而valueof    只能分析纯数字的String
     * 像 010 这样的8进制 他会解析成 =>10
     */
        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);
            // Handle sign, if present
            if (firstChar == '-') {
                negative = true;
                index++;
            } else if (firstChar == '+')
                index++;

            // Handle radix specifier, if present
            if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
                index += 2;
                radix = 16;
            }
            else if (nm.startsWith("#", index)) {
                index ++;
                radix = 16;
            }
            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 {
                result = Integer.valueOf(nm.substring(index), radix);
                result = negative ? Integer.valueOf(-result.intValue()) : result;
            } catch (NumberFormatException e) {
                // If number is Integer.MIN_VALUE, we'll end up here. The next line
                // handles this case, and causes any genuine format error to be
                // rethrown.
                String constant = negative ? ("-" + nm.substring(index))
                        : nm.substring(index);
                result = Integer.valueOf(constant, radix);
            }
            return result;
        }

        /**
         * 比较value值
         */
        public int compareTo(Integer anotherInteger) {
            return compare(this.value, anotherInteger.value);
        }
        //比较两个int大小
        public static int compare(int x, int y) {
            return (x < y) ? -1 : ((x == y) ? 0 : 1);
        }

        /**
         * 将两个数视为无符号比较,此时如果参数中不同号,结果会相反,同号的结果与compare()相同
         * ,任意一个参数如果有负数,加上MIN_VALUE,值会变成最大值
         */
        public static int compareUnsigned(int x, int y) {
            return compare(x + MIN_VALUE, y + MIN_VALUE);
        }

8 数学计算方法(重点,很多算法思想)

        /**
         * 返回i的二进制中最高位的1,其他全为0的值。
         * 比如i=10时,二进制即为1010,最高位的1,其他为0,则是1000
         * MIN_VALUE = 0x80000000  = 10000000000000000000000000000000  最高为1其他位为0 ,右移i的左边0的个数为得到i的最高位为1其他位为0的值,再 & 得到结果
         *  >>>: 无符号右移,不管正负高位都补0
         */
        public static int highestOneBit(int i) {
            return i & (MIN_VALUE >>> numberOfLeadingZeros(i));
        }

        /**
         *  获取int值补码形式前面的0的个数,0返回32,负数返回0
         *  该方法返回i的二进制从头开始有多少个0。i为0的话则有32个0。
         *  这里处理其实是体现了二分查找思想的,先看高16位是否为0,是的话则至少有16个0,否则左移16位继续往下判断,
         *  接着右移24位看是不是为0,是的话则至少有16+8=24个0,直到最后得到结果。
         */
        public static int numberOfLeadingZeros(int i) {
            // HD, Count leading 0's
            if (i <= 0)
                return i == 0 ? 32 : 0;
            int n = 31;
            if (i >= 1 << 16) { n -= 16; i >>>= 16; }
            if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
            if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
            if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
            return n - (i >>> 1);
        }

        /**
         * 与highestOneBit方法对应,lowestOneBit获取最低位1,其他全为0的值。
         * 先取负数,得到的结果和i进行与操作,即 原码 & 补码 结果刚好是加的那个1
         */
        public static int lowestOneBit(int i) {
            return i & -i;
        }

        /**
         * 该方法主要用于计算二进制数中1的个数。
         * 先将重要的列出来,
         *   0x55555555等于01010101010101010101010101010101,
         *   0x33333333等于00110011001100110011001100110011,
         *   0x0f0f0f0f等于00001111000011110000111100001111。
         *         0x3f等于00000000000000000000000000111111
         * 核心思想就是先每两位一组统计看有多少个1,比如10011111则每两位有1、1、2、2个1,记为01011010,
         * 然后再算每四位一组看有多少个1,而01011010则每四位有2、4个1,记为00100100,
         * 接着每8位一组就为00000110,接着16位,32位,最终在与0x3f进行与运算,得到的数即为1的个数
         * 分治思想
         */
        public static int bitCount(int i) {
            i = i - ((i >>> 1) & 0x55555555);
            i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
            i = (i + (i >>> 4)) & 0x0f0f0f0f;
            i = i + (i >>> 8);
            i = i + (i >>> 16);
            return i & 0x3f;
        }

        /**
         * 该方法即是将i进行反转,反转就是第1位与第32位对调,第二位与第31位对调,以此类推。
         * 核心思想是先将相邻两位进行对换,比如10100111对换为0101 1011,接着再将相邻四位两两进行对换,对换后为1010 1101,
         * 接着将相邻八位四四进行对换,最后字节对换,即把32位中间的16位对换,然后最高8位再和最低8位对换。
         * 用到了典型的分治思想,先将每个字节(8位)自己全部反转,然后再将四个字节进行反转,可能开始看有点绕,下面逻辑详细分析一下:
         *  比如现在有一个32位:  标记前8位数字为     1 2 3 4 5 6 7 8
         *                     第一次相邻对换后为:  2 1 4 3 6 5 8 7
         *                第二次相邻四个再两两对换:  4 3 2 1 8 7 6 5
         *                第三次相邻8个再四四对换:   8 7 6 5 4 3 2 1 刚好完成每个字节中的对换
         *                然后把32位四个字节进行对换得到结果,其中 1 刚好到了最后32位,以此类推
         */
        public static int reverse(int i) {
            i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
            i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
            i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
            return reverseBytes(i);
        }

        /**
         * 反转指定int值的字节数得到的值,即int 四个字节,第一个字节和最后一个字节调换位置,第二个和第三个调换位置
         * 核心思想: 将指定字节移动到指定位置,其他位置都置为0,然后|得出结果,
         */
        public static int reverseBytes(int i) {
            return (i << 24)            |  //左移24位,第四个字节移动到第一字节位置,后面全部补0
                    ((i & 0xff00) << 8)  |   //  0xff00= 00000000 00000000 11111111 00000000 , 获取第三个字节并移动八位到第二个字节,其他位置全部为0
                    ((i >>> 8) & 0xff00) |  // 无符号右移8位,第二字节移动到第三字节位置并 & 运算获取第三字节,其他位为0
                    (i >>> 24);        // 无符号右移24位,第一字节移动到第四字节位置,其他位为0, 全部 | 运算即为反转后的值
        }

        /**
         * 循环移位: 就是把数值变成二进制,然后循环移动的过程;
         * 换句话说,循环移位就是将移出的低位放到该数的高位(循环右移)或把移出的高位放到该数的低位(循环左移)
         * 比如: -2  10000000000000000000000000000010 补码为: 111111111111111111111111111111110
         * 左移2位,即把最高的两位  11 -> 放到低位右边为 11111111111111111111111111111011 = -5
         * 核心思想就是把左移或者右移的几位数(左移后面补零,右移前面补零),再通过右移或者左移到最后面或者最前面几位,然后一与(都是0,原来是什么就会得到什么结果)
         * 比如 -2 前面的 11 通过 >>> -2 (右移30位,移到最后面,刚好是左移补的零,达到循环)
         *           11 111111111111111111111111111000
         *           000000000000000000000000000000 11   |
         *           11111111111111111111111111111011
         */
        public static int rotateLeft(int i, int distance) {//左移
            return (i << distance) | (i >>> -distance);
        }
        public static int rotateRight(int i, int distance) {//右移
            return (i >>> distance) | (i << -distance);
        }

        /**
         * 正数返回1,负数返回-1,0返回0
         */
        public static int signum(int i) {
            return (i >> 31) | (-i >>> 31);
        }

        //@since 1.8 无符号除法
        public static int divideUnsigned(int dividend, int divisor) {
            return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
        }

        //@since 1.8 无符号求余数
        public static int remainderUnsigned(int dividend, int divisor) {
            return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
        }
        public static int sum(int a, int b) { return a + b; }
        public static int max(int a, int b) { return Math.max(a, b); }
        public static int min(int a, int b) { return Math.min(a, b); }

三 总结

Integer对象相等问题

    @Test
    public void test01(){
        Integer a=127;
        Integer b=127;
        System.out.println(a==b);// true  自动装箱会使用缓存中同一个对象

        Integer d=new Integer(127);
        Integer e=new Integer(127);
        System.out.println(d==e);   // false 使用new每次都是一个新对象

        Integer f=Integer.valueOf(127);
        Integer n=Integer.valueOf(127);
        System.out.println(f==n); // true  valueOf方法会使用缓存中的对象  [-128,hign(默认127)] 之间都是同一个对象
        Integer c=129;
        System.out.println(a==c); // false  不同对象
        System.out.println(a==b.intValue()); //true Integer会拆箱转为int,进行比较数值
        System.out.println(a.equals(b)); //true  比较基本数值的值
    }

四 Long类源码分析

Long类源码逻辑跟Integer基本差不多,好多API都是一样的,可对照Integer阅读即可!,这里就不贴详细分析了!

posted @ 2020-01-25 16:26  侯小厨  阅读(526)  评论(0编辑  收藏  举报
Fork me on Gitee