JDK源码解读之Integer(1)

本系列文章使用的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 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

static 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 =16
public static String toHexString(int i) {
    return toUnsignedString0(i, 4);
}

//转为八进制的表示形式,2^3 = 8
public static String toOctalString(int i) {
    return toUnsignedString0(i, 3);
}

//转为二进制的表示形式,2^1 = 2
public 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)
 */
@Override
public 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;
}
时间: 2024-10-11 07:04:00

JDK源码解读之Integer(1)的相关文章

jdk源码解读之ArrayList

直接上源码: 构造函数:     /**      * Constructs an empty list with an initial capacity of ten.      */     public ArrayList() {     this(10);     } 其实arrayList的本质是一个数据,只不过这个数组的大小可以变化.我们先来看下arraylist的数组是怎么定义的     /**      * Constructs an empty list with the sp

HashTable的故事----Jdk源码解读

HashTable的故事 很早之前,在讲HashMap的时候,我们就说过hash是散列,把...弄碎的意思.hashtable中的hash也是这个意思,而table呢,是指数据表格,也就是说hashtable的本意是指,一份被数据被打散,分散在各处的数据表格. HashTable,作为jdk中,极早提供的容器类(jdk1.0),同时是支持数据并发的类,其在项目中的使用却并不是很广泛.在我所经历的项目中,开发人员往往喜欢使用hashMap然后再通过锁,创造出线程安全的环境.即使是后来推出concu

JDK源码解读之toUnsignedString

我们知道,所有整数都是通过二进制编码的形式存储在内存中的.比如32位的整数,最高位是符号位,0代表正数,1代表负数. 那么怎么才能够将整数的二进制编码形式打印出来呢?Integer类提供了一个公有静态方法toBinaryString能够达到这一目的.我们来看看这段源码: public static String toBinaryString(int i) { return toUnsignedString(i, 1); } /** * Convert the integer to an unsi

JDK源码学习阅读-Integer类中的parseInt方法分析(转)

方法原型: public static int parseInt(String s,int radix): 输入:s表示待转换的字符串:radix表示需要转换成几进制的整数: 输出:返回一个32位整数. 算法流程图: JDK中的代码实现: 1 /** 2 * 字符串转换成整数 3 * @param s 待转换字符串 4 * @param radix 进制 5 * @return 6 */ 7 public static int parseInt(String s,int radix){ 8 //

HashSet的故事----Jdk源码解读

Hash,我们在说HashMap的时候,已经知道Hash是散列,Map是映射了. 那么Set又是什么呢 ? 先来看看Set的翻译是什么 n. [数] 集合:一套:布景:[机] 装置 这里Set所取的含义是集合.而且是数学概念上的集合.数学概念上的集合有什么特点呢?那就是Set中所有的元素不能重复.所以HashSet的意思就是以散列的形式维持一套不会有重复元素的集合. 接下来我们看看HashSet是怎么被Jdk实现的吧.(其实逻辑非常简单.) 类的声明: hashSet 继承自AbstractSe

JDK 源码解读之 Set接口

public interface Set<E> extends Collection<E> { //Set很简单,扩展了Collection Set<E> 和 Collection<E> 都带了<E>,是泛型接口.什么是泛型类,泛型接口呢?Oracle官方文档上是这么说的: A generic class is defined with the following format: class name<T1, T2, ..., Tn>

JDK 源码解读之 ArrayList

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable 文档中提到:size isEmpty get set iterator listIterator 操作,是( run in constant time), add操作是(run in amortized constant time),而 其他

JDK 源码解读之 Number类

public abstract class Number implements java.io.Serializable { Number类有修饰符 abstract .表明Number类定义了一些方法,并没有具体实现,需要子类自己实现,关于abstract ,quaro上一个答案写的很清晰: The "abstract" Keyword The keyword abstract can be used on classe declaration. For example abstra

Java之ArrayList源码解读(JDK 1.8)

java.util.ArrayList 详细注释了ArrayList的实现,基于JDK 1.8 . 迭代器SubList部分未详细解释,会放到其他源码解读里面.此处重点关注ArrayList本身实现. 没有采用标准的注释,并适当调整了代码的缩进以方便介绍 import java.util.AbstractList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; import java.