本系列文章使用的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;
}
转载于:https://blog.51cto.com/acesdream/1969368