JDK源码学习笔记——Integer

时间:2024-12-20 08:33:50

一、类定义

public final class Integer extends Number implements Comparable<Integer>

二、属性

    private final int value;// fianl
private static final long serialVersionUID = 1360826667806852920L;
// 值为 (-(2的31次方)) 的常量,它表示 int 类型能够表示的最小值。
public static final int MIN_VALUE = 0x80000000;
// 值为 ((2的31次方)-1) 的常量,它表示 int 类型能够表示的最大值。
public static final int MAX_VALUE = 0x7fffffff;
// 表示基本类型 int 的 Class 实例。
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
// 用来以二进制补码形式表示 int 值的比特位数。
public static final int SIZE = 32;
// 用来以二进制补码形式表示 int 值的字节数。1.8以后才有
public static final int BYTES = SIZE / Byte.SIZE;
// 用来取两位数的十位数字
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',
} ;
// 用来取不同进制的某一位数字
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'
};
// 用来确定十进制位数
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };

private final int value;

    // value是final的
Integer i = new Integer(10);
i = 5;
// 反编译之后
Integer i = new Integer(10);
i = Integer.valueOf(5);

三、构造方法

   // 两个构造方法  初始化一个Integer对象的时候只能创建一个十进制的整数
public Integer(int value) {
this.value = value;
} public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);

四、主要方法

Integer.valueof()

     /**
* 1.Integer类加载时,初始化一个-128到127的数组缓存
* 2.调用valueOf(int i)时,IntegerCache.cache中有直接取,IntegerCache.cache中没有需要new Integer
* 3.创建Integer时,Integer i = 5(编译后Integer i = Integer.valueOf(5));或者直接用Integer.valueOf(5)
* 4.-Djava.lang.Integer.IntegerCache.high=xxx就可以改变缓存值的最大值
*/ public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
} public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
} public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
} 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 =
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; 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() {}
}

String--->Integer

    Integer getInteger(String nm)
Integer getInteger(String nm, int val)
Integer getInteger(String nm, Integer val)
Integer decode(String nm)
Integer valueOf(String s)
Integer valueOf(String s, int radix)
int parseUnsignedInt(String s)
int parseUnsignedInt(String s, int radix)
int parseInt(String s)
int parseInt(String s, int radix) // 调用栈
getInteger(String nm) ---> getInteger(nm, null);--->Integer.decode()--->Integer.valueOf()--->parseInt() // parseInt()主要代码
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
// 思路:357 = 3*10^2+5*10^1+7*10^0 = ((3*10+5)*10+7);
// 用负数计算原因:用正数计算表示不了Integer.MIN_VALUE = 0x80000000;

Integer--->String

   String toString()
static String toString(int i)
static String toString(int i, int radix)
static String toBinaryString(int i)
static String toHexString(int i)
static String toOctalString(int i)
static String toUnsignedString(int i)
static String toUnsignedString(int i, int radix) public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);// 计算字符数(根据sizeTable属性)
char[] buf = new char[size];
getChars(i, size, buf);// int-->char数组
return new String(buf, true);
} /**
* 计算字符数(根据sizeTable属性)
* 1.局部性原理之空间局部性:sizeTable为数组,存储在相邻的位置,cpu一次加载一个块数据数据到cache中(多个数组数据),此后访问sizeTable 不需要访问内存
* 2.基于范围的查找,是很实用的设计技术
*/
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
} /**
* int-->char数组
* 1.取余的思想
* 2.移位和加法的效率比直接乘除的效率要高,乘法的效率比除法的效率要高
* 3.分while for两段循环原因:大于65536的数乘52429超过int最大值,溢出
* 4.选52429原因:保证(i * num2) >>> (num3)结果接近于0.1,52429/2^19精度小
* 5.选65536原因:①65536=2^16 2^16 * 52429 < 2^32 < 2^17 * 52429
* ②q = (i * 52429) >>> (16+3); >>>无视符号位补0 --> i*52429只要小于2^32次方即可
* 6.r = i - ((q << 3) + (q << 1)); 移位和加法代替乘法
* q = (i * 52429) >>> (16+3); 移位和乘法代替除法
* buf [--charPos] = DigitOnes[r]; 直接取十位数字,代替再除一次取余
*/
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0; if (i < 0) {
sign = '-';
i = -i;
} // 每次循环过后,都会将i中的走后两位保存到字符数组buf中的最后两位中,读者可以将数字i设置为12345678测试一下,
// 第一次循环结束之后,buf[7] = 8,buf[6]=7。第二次循环结束之后,buf[5] = 6,buf[4] = 5。
while (i >= 65536) {
q = i / 100;
r = i - ((q << 6) + (q << 5) + (q << 2));// really: r = i - (q * 100);
i = q;
buf [--charPos] = DigitOnes[r];// 取DigitOnes[r]的目的其实取数字r%10的结果
buf [--charPos] = DigitTens[r];// 取DigitTens[r]的目的其实是取数字r/10的结果
} // 循环将其他数字存入字符数组中空余位置
for (;;) {
q = (i * 52429) >>> (16+3);// 这里其实就是除以10。取数52429和16+3的原因在后文分析。
r = i - ((q << 3) + (q << 1));// r = i-(q*10) ...
// 将数字i的最后一位存入字符数组,
// 还是12345678那个例子,这个for循环第一次结束后,buf[3]=4。
buf [--charPos] = digits [r];
i = q;
// for循环结束后,buf内容为“12345678”;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
    Integer s = new Integer(5);
System.out.println(s + "");
// 反编译:
Integer s = new Integer(5);
System.out.println((new StringBuilder()).append(s).append("").toString());

五、其他方法

    // 无符号转换
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
} /**
* 该方法主要用于计算二进制数中1的个数。
* 0x55555555等于01010101010101010101010101010101,0x33333333等于110011001100110011001100110011,0x0f0f0f0f等于1111000011110000111100001111。
* 它的核心思想就是先每两位一组统计看有多少个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,其他全为0的值。
* 比如i=10时,二进制即为1010,最高位的1,其他为0,则是1000。如果i=0,则返回0。如果i为负数则固定返回-2147483648,因为负数的最高位一定是1,即有1000,0000,0000,0000,0000,0000,0000,0000。
* 将i右移一位再或操作,则最高位1的右边也为1了,接着再右移两位并或操作,则右边1+2=3位都为1了,接着1+2+4=7位都为1,直到1+2+4+8+16=31都为1,最后用i - (i >>> 1)自然得到最终结果。
*/
public static int highestOneBit(int i) {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
} /**
* 获取最低位1,其他全为0的值。
* 先取负数,这个过程需要对正数的i取反码然后再加1,得到的结果和i进行与操作,刚好就是最低位1其他为0的值了
*/
public static int lowestOneBit(int i) {
return i & -i;
} /**
* 该方法返回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 32;
int n = 1;
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 -= i >>> 31;
return n;
} /**
* 该方法返回i的二进制从尾开始有多少个0。它的思想和前面的类似,也是基于二分查找思想,详细步骤不再赘述。
*/
public static int numberOfTrailingZeros(int i) {
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);
} /**
* 该方法即是将i进行反转,反转就是第1位与第32位对调,第二位与第31位对调,以此类推。
* 它的核心思想是先将相邻两位进行对换,比如10100111对换01011011,接着再将相邻四位进行对换,对换后为10101101,接着将相邻八位进行对换,最后把32位中中间的16位对换,然后最高8位再和最低8位对换。
*/
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;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}

参考资料:

1、Java 源码学习系列(三)——Integer

2、Java源码 Integer.bitCount实现过程

3、Java中byte做&0xff运算的原因及解析

4、从JDK源码角度看Integer

5、Integer源码详解