JDK源码分析----Integer
时间:2014-02-08 01:20:21
收藏:0
阅读:348
1. Integer的缓存技术
JDK1.5后Java引入了自动装箱和自动拆箱技术,
Integer ina = 2; Integer inb = 2; System.out.println("装箱后 "+(ina == inb)); Integer inc = 200; Integer ind = 200; System.out.println("装箱后"+(inc == ind));
上面的执行结果分别为true和false.为什么两次装箱结果不同呢?这是由于java的Integer在实现时有这样一个内部类,
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) { 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); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
不难发现,-128到127之间的整数会在第一次使用时(类加载时)被放在一个叫cache的数组里。当然这个大小区间可以改变JVM的设置来改变。
并且,Integer的静态方法valueOf(int i)也使用了该数组。
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
2. 一个整数在给定进制的字符串表示
toString(int i , int radix)
char buf[] = new char[33]; boolean negative = (i < 0); int charPos = 32; if(negative) { 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));
以上是核心代码,实际上在JDK源码里是统一化成负数处理。笔者觉得这不符合习惯,此次改为统一化为正数处理。至于这里为什么数组长度为33也是明显的,因为java里int有32位,加上可能的符号位。
3. 一个整数的长度
static int stringSize(int x)
这个函数不是个public权限的函数,作为内部工具方法使用。
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; // Requires positive x static int stringSize(int x) { for (int i=0; ; i++) if (x <= sizeTable[i]) return i+1; }
这个方法的实现是很巧妙的,避免除法、求余等,判断条件简单,效率高(采用静态field分析,而不是负责逻辑判断可以明显提高效果)。(int 最大长只有10)
4. toString()的实现
可能有人觉得上面的toString(int i, int radix)已经是通用算法了,但是JDK在并没有这样(即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); }
这个算法的核心是getChars的实现,即将一个整数高效地逐位存入一个char数组中。
static void getChars(int i, int index, char[] buf) { int q, r; int charPos = index; char sign = 0; if (i < 0) { sign = ‘-‘; i = -i; }
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]; }
这个处理大数部分,其中DigitOnes和DigitTens分别如下,
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‘, } ;
上面while部分的思想是,DigitOnes是代表个位,DigitTens代表十位,每次r可以迭代两位(r就是除以100的余数)。至于移位运算,是为了提高运算速度,q*100 = q*(2^6) +q*(2^5) + q*(2^2) = 64q+32q+4q.
然后对小数采用更快速的方式,
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; }
上面操作的作用是q得到i截断个位的值.(q = i / 10 ).至于采用上述复杂的移位的目的是提高速度(>>>无符号右移).
原文:http://blog.csdn.net/chenloveit/article/details/18969459
评论(0)