zoukankan      html  css  js  c++  java
  • 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阅读即可!,这里就不贴详细分析了!

  • 相关阅读:
    百度网盘下载太慢,试试阿里云网盘?
    linux使用过程中遇到的常见问题
    vscode设置护眼色
    为什么程序员互相之间不能透露薪水?
    机器学习:支持向量机(SVM)
    Java多线程总结(三)
    Java多线程总结(二)
    Java多线程总结(一)
    8.多线程--避免活跃性危险
    7.多线程--线程池的使用
  • 原文地址:https://www.cnblogs.com/houzheng/p/12233150.html
Copyright © 2011-2022 走看看