JDK源码解读之Integer(1)

时间:2022-12-28 08:13:09

        本系列文章使用的JDK版本为jdk1.8.0_131,一些基础的知识储备:原码、反码、补码,移位,建议参考文章:《原码,反码,补码 详解》《Java 源码学习系列(三)――Integer

        Integer是我们开发过程中最常用的一个类,因此JDK的源码解读就从它开始吧。凡是对Java有点了解的都知道,Integer是int的包装类型,长度为32位。因此我们可以看到如下定义

//可表示的最小值:-2^31,至于为什么是这个数,上面的文章讲的很清楚了
@Native public static final int   MIN_VALUE = 0x80000000;
//可表示的最大值:2^21-1
@Native public static final int   MAX_VALUE = 0x7fffffff;
//Integer是int的包装类
public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");

/**
 * 表示int使用多少位
 *
 * @since 1.5
 */
@Native public static final int SIZE = 32;

/**
 * 表示int使用多少字节,一个字节是8位
 *
 * @since 1.8
 */
public static final int BYTES = SIZE / Byte.SIZE;
/**
 * 存放int的值,final类型的,说明不可更改
 *
 * @serial
 */
private final int value;

/**
 * Integer构造方法,使用int
 */
public Integer(int value) {
    this.value = value;
}

/**
 * Integer构造方法,使用字符串,实际上把string转为十进制int
 */
public Integer(String s) throws NumberFormatException {
    this.value = parseInt(s, 10);
}

        这个数组是干嘛的呢?我们都知道数字是有0-9,十六进制使用了0-9和a-f(10-15),所以这个数组就是为了进行不同进制之间转换时使用的常量数组,最小可以表示2进制,最大可以表示36进制(10个数字加26个字母)

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'};

toString是怎么样实现的?

//i:待转换的参数;radix:转换的基数(多少进制)public static String toString(int i, int radix) {    //radix < 2 || radix > 36,则设置为10,为啥是36,因为上面有36个字符    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)        radix = 10;    /* 如果是十进制的话,使用下面的toString(int i) */    if (radix == 10) {        return toString(i);    }    //其实如果是十进制的话,也可以使用下面的方法,之所以没有用就是出于效率的考虑    char buf[] = new char[33];    //如果是负数negative是true    boolean negative = (i < 0);    int charPos = 32;        //如果不是负数,转为负数统一处理    if (!negative) {        i = -i;    }        //如果i小于进制的话,循环处理    while (i <= -radix) {            //取余数        buf[charPos--] = digits[-(i % radix)];        //求商        i = i / radix;    }        buf[charPos] = digits[-i];    if (negative) {        buf[--charPos] = '-';    }    return new String(buf, charPos, (33 - charPos));}//把int按照十进制,转为字符串public static String toString(int i) {    //如果i是最小值的话,直接返回    if (i == Integer.MIN_VALUE)        return "-2147483648";    //获取转换后的字符串长度,如果是负数的话,需要符号为(-),所以返回的长度+1    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);    //定义相应长度的字符数组    char[] buf = new char[size];    //这个方法是关键,i待转换的int参数,size转换之后的字符串长度,buf字符数组    getChars(i, size, buf);    return new String(buf, true);}//这个数组是为了进行快速判断长度定义的数组,分别代表1位,2位,超过9位,不超过最大值final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,                                      99999999, 999999999, Integer.MAX_VALUE };// int转为字符串的长度static int stringSize(int x) {    for (int i=0; ; i++)        if (x <= sizeTable[i])            //为啥是加1,因为数组下标i,代表的长度是i+1            return i+1;}//十位数的数组定义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',    } ;上面的两个数组怎么来的呢?看下面的数字矩阵,把十位数上的数字作为DigitTens数组,个位数上的数字作为DigitOnes,是一样的吧。00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 1920 21 22 23 24 25 26 27 28 2930 31 32 33 34 35 36 37 38 3940 41 42 43 44 45 46 47 48 4950 51 52 53 54 55 56 57 58 5960 61 62 63 64 65 66 67 68 6970 71 72 73 74 75 76 77 78 7980 81 82 83 84 85 86 87 88 8990 91 92 93 94 95 96 97 98 99static void getChars(int i, int index, char[] buf) {    int q, r;    int charPos = index;    char sign = 0;    //如果是负数,定义符号位:-,之后把i转换为正数处理    if (i < 0) {        sign = '-';        i = -i;    }    // i大于65536时,一次生成两位    while (i >= 65536) {        q = i / 100;        // really: r = i - (q * 100);        //q << 6相当于q*2^6,所以:q*2^6+q*2^5+q*2^2=q*(2^6+2^5+2^2)=q*100        //为什么用移位,不用上面的操作,效率问题        r = i - ((q << 6) + (q << 5) + (q << 2));        //说白了上面的几部就是获取余数r = i % 100;                //i设置为i除以100的商        i = q;                //赋值,分别放到个位和十位上,以27为例:DigitOnes[27]='7',DigitTens[27]='2'        buf [--charPos] = DigitOnes[r];        buf [--charPos] = DigitTens[r];    }    // Fall thru to fast mode for smaller numbers    // assert(i <= 65536, i);    for (;;) {        //这里和q = i / 10的效果一样的,但是为什么没用呢?因为计算精度是够用的,        //2^19 = 524288,double s = 52429 / 524288 = 0.1000003814697266        //为什么是无符号右移(>>>),因为65536*52429溢出了        q = (i * 52429) >>> (16+3);        r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...        //上面几部就是获取余数 r = i % 10;        buf [--charPos] = digits [r];        i = q;        if (i == 0) break;    }    //最后设置符号位    if (sign != 0) {        buf [--charPos] = sign;    }}


toUnsignedString是怎么实现的?

//1、首先转为无符号的long,然后调用Long的转换方法public static String toUnsignedString(int i, int radix) {    return Long.toUnsignedString(toUnsignedLong(i), radix);}/**int 转为无符号long型,需要做到:高32位均为0,低32位等于这个int型参数的比特位,非负的int转为相等的long,负数转为输入值+2^32次方*/public static long toUnsignedLong(int x) {    //0xffffffffL表示32个1,和x做‘与’操作,可以确保,高位为0,低位保持不变    return ((long) x) & 0xffffffffL;}//该方法与上面的方法一样,只不过是直接按照十进制去转public static String toUnsignedString(int i) {    return Long.toString(toUnsignedLong(i));}


int转为不同进制的字符串表示

//转为16进制的表示形式,为什么是4,详见下面formatUnsignedInt方法的实现;2^4 =16public static String toHexString(int i) {    return toUnsignedString0(i, 4);}//转为八进制的表示形式,2^3 = 8public static String toOctalString(int i) {    return toUnsignedString0(i, 3);}//转为二进制的表示形式,2^1 = 2public static String toBinaryString(int i) {    return toUnsignedString0(i, 1);}private static String toUnsignedString0(int val, int shift) {    // assert shift > 0 && shift <=5 : "Illegal shift value";断言为1-5    //Integer.numberOfLeadingZeros(val);负数返回0,0返回32    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);    //如果mag=0的话,说明是0,chars=1;否则为(mag+(shift-1))/shift    int chars = Math.max(((mag + (shift - 1)) / shift), 1);    char[] buf = new char[chars];    formatUnsignedInt(val, shift, buf, 0, chars);    // Use special constructor which takes over "buf".    return new String(buf, true);}/** * 在指定 int 值的二进制补码表示形式中最高位(最左边)的 1 位之前,返回零位的数量。 * 如果指定值在其二进制补码表示形式中不存在 1 位,换句话说,如果它等于零,则返回 32。  * 说白了就是找从左边数0的个数,知道发现1为止,就是找第一个1的位置, * 负数返回0,因为负数的最高位为1 * @since 1.5 */public static int numberOfLeadingZeros(int i) {    // HD, Figure 5-6    if (i == 0)        return 32;    int n = 1;    //int是32位,为什么是16、8、4、2,这是使用了二分查找方法    //i先无符号右移16位,说明高16位位0,低16位位i的高16位,如果是0,说明i的前16位都是0,    //然后i左移16位,左移之后,相当于i的高16位是之前的低16位,低十六位都是0    if (i >>> 16 == 0) { n += 16; i <<= 16; }    if (i >>> 24 == 0) { n +=  8; i <<=  8; }    if (i >>> 28 == 0) { n +=  4; i <<=  4; }    if (i >>> 30 == 0) { n +=  2; i <<=  2; }    //判断符号位n = n - i;    n -= i >>> 31;    return n;}static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {    int charPos = len;    //基数,进制数=1 * 2^shift;这也是上面为什么转为16进制传4,8进制传3,二进制传1的原因    int radix = 1 << shift;    int mask = radix - 1;    do {        //val & mask:为什么会落在0-mask?        //以16进制为例,那么shift为4,那么raidx=16,mask=15,15的二进制,补码形式高位为0,        //只有低4位为1;两个数进行与操作,相当于保留了val的低4位        buf[offset + --charPos] = Integer.digits[val & mask];        //其实就是val = val / radix;        val >>>= shift;    } while (val != 0 && charPos > 0);    return charPos;}

parseInt的实现:把字符串根据进制数,转为int

/** * 把字符串和进制数作为参数,转为int * * <p>Examples: * <blockquote><pre> * parseInt("0", 10) returns 0 * parseInt("473", 10) returns 473 * parseInt("+42", 10) returns 42 * parseInt("-0", 10) returns 0 * parseInt("-FF", 16) returns -255 * parseInt("1100110", 2) returns 102 * parseInt("2147483647", 10) returns 2147483647 * parseInt("-2147483648", 10) returns -2147483648 * parseInt("2147483648", 10) throws a NumberFormatException * parseInt("99", 8) throws a NumberFormatException * parseInt("Kona", 10) throws a NumberFormatException * parseInt("Kona", 27) returns 411787 * </pre></blockquote> * * @param      s   the {@code String} containing the integer *                  representation to be parsed * @param      radix   the radix to be used while parsing {@code s}. * @return     the integer represented by the string argument in the *             specified radix. * @exception  NumberFormatException if the {@code String} *             does not contain a parsable {@code int}. */public static int parseInt(String s, int radix)            throws NumberFormatException{    /*     * 如果字符串是空,抛出异常     */    if (s == null) {        throw new NumberFormatException("null");    }    //如果redix小于2,抛出异常    if (radix < Character.MIN_RADIX) {        throw new NumberFormatException("radix " + radix +                                        " less than Character.MIN_RADIX");    }    //如果redix大于36,抛出异常    if (radix > Character.MAX_RADIX) {        throw new NumberFormatException("radix " + radix +                                        " greater than Character.MAX_RADIX");    }    int result = 0;    boolean negative = false;    int i = 0, len = s.length();    int limit = -Integer.MAX_VALUE;    int multmin;    int digit;    if (len > 0) {        char firstChar = s.charAt(0);        if (firstChar < '0') { // 第一位可能是‘+’或者‘-’            if (firstChar == '-') {                //说明是负数,设置limit为Integer.MIN_VALUE                negative = true;                limit = Integer.MIN_VALUE;            } else if (firstChar != '+')                //如果不是‘+’,抛出异常                throw NumberFormatException.forInputString(s);            if (len == 1) // 不能只有一个‘+’或者‘-’                throw NumberFormatException.forInputString(s);            i++;        }                //如果是正数,limit为-Integer.MAX_VALUE,如果是正数limit为Integer.MIN_VALUE                multmin = limit / radix;        while (i < len) {            //下面这段代码,各种防止越界            // 根据字符和进制获取字符对应的int数值,后面会分析Character            digit = Character.digit(s.charAt(i++),radix);            if (digit < 0) {                throw NumberFormatException.forInputString(s);            }            //避免result = result * radix越界,因为multmin已经是最小值了            if (result < multmin) {                throw NumberFormatException.forInputString(s);            }            result *= radix;            //防止越界,result-digit < limit;            //limit已经是最小值了,如果小于了,肯定发生了越界            if (result < limit + digit) {                throw NumberFormatException.forInputString(s);            }            result -= digit;        }    } else {        //如果是空串,抛出异常        throw NumberFormatException.forInputString(s);    }    //如果是负数,直接返回,否则转为正数    return negative ? result : -result;}/** * 调用上面的方法 */public static int parseInt(String s) throws NumberFormatException {    return parseInt(s,10);}/** * 获取无符号型int * @since 1.8 */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 {            //如果字符串长度不超过5位,或者是十进制,长度不超过9位,都可以用上面的方法去转            if (len <= 5 || // Integer.MAX_VALUE 使用36进制表示法是6位                (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE 使用十进制表示法是10位                return parseInt(s, radix);            } else {                //否则的话,转为long                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);    }}/** * 调用上面的方法 * @since 1.8 */public static int parseUnsignedInt(String s) throws NumberFormatException {    return parseUnsignedInt(s, 10);}


Integer.valueOf()方法的实现:看了这个地方,就应该知道为什么使用Integer.valueOf(int i)来创建Integer对象效率高了。

/** * 根据字符串和进制数,获取一个Integer对象,调用Integer valueOf(int i)方法 */public static Integer valueOf(String s, int radix) throws NumberFormatException {    return Integer.valueOf(parseInt(s,radix));}/** * 根据字符串,获取一个Integer对象,默认采用十进制,调用Integer valueOf(int i)方法 */public static Integer valueOf(String s) throws NumberFormatException {    return Integer.valueOf(parseInt(s, 10));}/** * Integer缓存,缓存的范围是-128到127,在第一次使用的时候初始化 * 可以通过-XX:AutoBoxCacheMax=<size>设置,在虚拟机初始化的时候, * 属性java.lang.Integer.IntegerCache.high被设置保存在是有系统属性中 * 在sun.misc.VM类中 */private static class IntegerCache {    static final int low = -128;    static final int high;    static final Integer cache[];    static {        // 可以修改这个缓存的最大值        int h = 127;        String integerCacheHighPropValue =            sun.misc.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;        //在初始化的时候把-128到127提前创建好        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 IntegerCache.high >= 127;    }    private IntegerCache() {}}/** * 如果在缓存的范围,直接返回缓存的对象,否则创建对象,因此建议使用下面的方法创建Integer * * @param  i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since  1.5 */public static Integer valueOf(int i) {    if (i >= IntegerCache.low && i <= IntegerCache.high)        return IntegerCache.cache[i + (-IntegerCache.low)];    return new Integer(i);}

hashCode和equals的实现:

/** * Integer的hashCode就是int的值(value) */@Overridepublic int hashCode() {    return Integer.hashCode(value);}/** * 返回value作为hashCode */public static int hashCode(int value) {    return value;}/** * equals,比较的是两个intValue是否相等, */public boolean equals(Object obj) {    if (obj instanceof Integer) {        return value == ((Integer)obj).intValue();    }    return false;}

从系统属性获取Integer

/** * 从系统属性文件中获取int值,nm为属性的key */public static Integer getInteger(String nm) {    return getInteger(nm, null);}/** * 从系统属性文件中获取int值,nm为属性的key,val为默认值 * 如果没有key为nm的值,则返回val */public static Integer getInteger(String nm, int val) {    Integer result = getInteger(nm, null);    return (result == null) ? Integer.valueOf(val) : result;}/** * 从系统属性文件中获取int值,nm为属性的key,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 {            return Integer.decode(v);        } catch (NumberFormatException e) {        }    }    return val;}/** * 把字符串解析为Integer */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;    }    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;}

compareTo方法的实现:

/** * Integer对象的比较 */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);}/** * 无符号比较, */public static int compareUnsigned(int x, int y) {    return compare(x + MIN_VALUE, y + MIN_VALUE);}

Integer中的一些位运算

/** *  * 获取i的最高位的1,右边补零,如果i是负数,返回Integer.MIN_VALUE; * 如果i是0,返回0; * 如果i是1,返回1; * 如果i是5,返回4; */public static int highestOneBit(int i) {    //假设i=5,则补码为:00000000000000000000000000001001    // i 和 (i >> 1)进行或操作,i = 00000000000000000000000000001101,    //相当于从最高位开始的两位为1    i |= (i >>  1);    //i = 00000000000000000000000000001111,相当于从最高位开始的四位为1    i |= (i >>  2);    //最高位1开始的前8位变为1,,因为i的最高位在第4位,因此右移四位,就是0,    // 因此i不变,i = 00000000000000000000000000001111    i |= (i >>  4);    //最高位1开始的前16位变为1    i |= (i >>  8);    //最高位1开始的前32位变为1,i = 00000000000000000000000000001111    i |= (i >> 16);    //i >>> 1之后,i=00000000000000000000000000000111    return i - (i >>> 1);}/** *  * 获取i的最低位的1,右边补零 */public static int lowestOneBit(int i) {    // 正数:原码,反码,补码一样;负数:补码为原码的反码+1,jvm中使用补码,    //所以,二者进行与操作,可得到最低位的1    return i & -i;}/** * 最高位的1左边的0的个数,负数返回0,如果是0,返回32 * @since 1.5 */public static int numberOfLeadingZeros(int i) {    // HD, Figure 5-6    if (i == 0)        return 32;    int n = 1;    //以i=5,即i=00000000000000000000000000001001    //二分查找法,先查看高16位,如果是0,n = 1+ 16;i左移16位,即i的低十六位,变为高十六位    //n = 1+16; i = 00000000000010010000000000000000    if (i >>> 16 == 0) { n += 16; i <<= 16; }    //n = 17 + 8; i = 00001001000000000000000000000000    if (i >>> 24 == 0) { n +=  8; i <<=  8; }    //n = 25+4; i = 10010000000000000000000000000000    if (i >>> 28 == 0) { n +=  4; i <<=  4; }    //i>>>30,不等于0    if (i >>> 30 == 0) { n +=  2; i <<=  2; }    //n = 29, i=10010000000000000000000000000000    n -= i >>> 31;    return n;}/** * 最低位1的最右边的0的个数,如果是0,返回32 * 和上面的方法类似,二分查找 * @since 1.5 */public static int numberOfTrailingZeros(int i) {    // HD, Figure 5-14    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);}/** * 二进制中1的个数 *  * http://blog.csdn.net/cor_twi/article/details/53720640  * * @since 1.5 */public static int bitCount(int i) {    // HD, Figure 5-2    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;}




本文出自 “路飞的弟弟路痴” 博客,请务必保留此出处http://acesdream.blog.51cto.com/10029622/1969368