Integer是int的的包装类,java虚拟机在两者之间提供了自动装包和拆包机制.
toString(int i),toString(int i, int radix)
返回用第二个参数指定基数表示的第一个参数的字符串表示形式,如果第二个参数不指定则默认返回10进制.
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
//取出十位数的数字。这里设计的很巧妙,连续的10位数保存的值是该数组地址的十位数.所以输入任意的两位数就可以直接获得十位数的数字.
//下面数组可以看做一张表格,行表示个位数,列表示十位数. 行,列的范围都是0-10. 根据该坐标可以直接从数组中获取得到对应的十位数字.这里的做法就是将每一行都设置为相同的数字,即十位数的数字.
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',
} ;
//取出个位数的数字,输入任意两位数能获得其个位上的数字,这里的做法是,num%10的位置存放num%10的值.
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',
} ;
代码中将(q * 100)的计算转化求解((q << 6) + (q << 5) + (q << 2)).这样做是否效率会有所提高呢?
如果我们自己去实现的话,对于十进制一般做法是循环地对10求余数,然后再除以10不断循环知道结果为0.
Integer 缓存
为提高效率,JDK将[-128,127]之间的这些常用的int值的Integer对象进行了缓存。这是通过一个静态内部类来实现的。代码如下:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
int h = 127;
//代码省略
...
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
//为-128到127之间的每个数字都设置了缓冲
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
valueOf方法内部实现是基于IntegerCache,如果参数值在-128~127范围内则返回缓冲中的实例对象,否则创建一个新的实例,代码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这也就解释了为什么会有如下的结果:
1 Integer a1 = Integer.valueOf(13);
2 Integer a2 = Integer.valueOf(13);
3 Integer a3 = Integer.valueOf(133);
4 Integer a4 = Integer.valueOf(133);
5 System.out.println(a1 == a2); //true
6 System.out.println(a3 == a4); //false
Integer缓冲的应用很广,除了valueOf方法里使用到该缓冲,自动包装机制其实也是采用了缓冲机制,即Integer i01 = 59; i01的值是从缓冲中获取得到.但Integer b01 =133.是创建了一个新的对象.所以:
Integer i01 = 59; //自动装箱,内部应该是采用了和valueOf()一样的生成机制生成一个对象.
int i02 = 59; //基本类型
Integer i03 =Integer.valueOf(59); //59值在缓冲范围内,所以直接从缓冲中取得
Integer i04 = new Integer(59); //明确生成一个新的对象.
System.out.println(i01== i02); //true,与基本类型比较时是直接比较值
System.out.println(i01== i03); //true, 说明两者都是从缓冲中取得
System.out.println(i03== i04); //false i04是新建对象,这里比的是地址.
System.out.println(i02== i04); //true 和基本类型比较时直接比较值,而不是地址.
System.out.println(i01== i04); //false 比较地址,i01是从缓冲中取得的.
//当值超过了缓冲范围则:
Integer a01 = 133;
int a02 = 133;
Integer a03 =Integer.valueOf(133);
Integer a04 = new Integer(133);
System.out.println(a01== a02);// true 基本类型与包装类的比较
System.out.println(a01== a03); //false 比较地址,因为133超过了缓冲范围,所以两者都是创建新的对象.
System.out.println(a03== a04); //false
System.out.println(a02== a04); // true
System.out.println(a01== a04); // false 比较地址
以上代码可以总结得到一下内容:
- 基本类型与包装类比较时是比较数值
- 自动装箱操作,即将一个int变量直接赋值给Integer变量,内部采用了和valueOf一样的生成机制.即如果数值在缓冲范围,则直接从缓冲中取得一个实例.否则生成一个实例对象.