Integer是java中的基础类,在lang包中,它是int类型的包装类。所以还是有必要看下源码的。
一、类继承关系图:
1、继承了Number抽象类,其实基本类型的包装类除了Boolean外,其他都继承了Number,里面主要一些转换值的方法
2、实现了Comparable接口,说明可以作排序的
3、实现了Serializable接口,可以作序列化
二、继承,实现哪些方法
三、基本的属性
// integer能表示的最小值 -2147483648
@Native public static final int MIN_VALUE = 0x80000000;
// integer能表示的最小值 2147483647
@Native public static final int MAX_VALUE = 0x7fffffff;
//用32位表示数值范围
@Native public static final int SIZE = 32;
//4个字节
public static final int BYTES = SIZE / Byte.SIZE;
//字符数组
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'
};
//取0~99之间数字的十位的数字
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',
} ;
//取0~99之间数字的个位的数字
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 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;
}
内部私有类:IntegerCache
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);
//获取配置文件和127之间的最大值
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() {}
}
从上面可以看出,默认会将-128 ~ 127范围的数字生成Integer对象缓存起来
所以会有:
// A code block
Integer j = 66
Integer k = 66
j == k; // 输出:true
Integer e = 200
Integer h = 200
e == h; //输出:false
因为 j 和 k 都是取得缓存里的,是同一个对象,而 e 和 h 不在缓存里,系统自动装箱new出来的。
基本方法
1、 valueOf(int i) 得到一个Integer对象
public static Integer valueOf(int i) {
//首先会在缓存中取,否则直接new
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
2、toString方法
上面提到Integer类重写了Object的toString方法,但内部最中还是调了
public static String toString(int i) {
//最小值
if (i == Integer.MIN_VALUE)
return "-2147483648";
//获取 i 对应的字符串长度,如果是负数符号位也算1个长度
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
//创建字符数组
char[] buf = new char[size];
//获取 i 对应的字符数组
getChars(i, size, buf);
return new String(buf, true);
}
接下来看getChars方法
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;//符号位
if (i < 0) {
sign = '-';
i = -i;//变成正整数
}
//当大于65536的时候每两位开始操作 假设i=65536
while (i >= 65536) {
//65536 / 100 = 655
q = i / 100;
//65536 - 655*100 = 36 这里使用了技巧,(q << 6) + (q << 5) + (q << 2)相
//于q*100, 同时也证明位移和加法性能高于乘法
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
//得到36的个位6,放数组到最后一位
buf [--charPos] = DigitOnes[r];
//得到36的个位3,依次放入
buf [--charPos] = DigitTens[r];
}
//对于较小的数字,请切换到快速模式,一位一位处理
// assert(i <= 65536, i);
for (;;) {
//相当于除以10 同时证明乘法和移位的效率要高于除法, 这里用(16+3),是因为最接近
//除以10的效果
q = (i * 52429) >>> (16+3);
// r = i-(q*10) (q << 3) + (q << 1)相当于q*10...
r = i - ((q << 3) + (q << 1));
buf [--charPos] = digits [r];//放到数组
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;//把符号放入
}
}
从上面的方法可以看到除了代码写的十分优雅、飘逸,对性能的要求是十分苛刻,那怕最求那一点点的速度。
未完待续!