java.lang基础数据类型boolean、char、byte、short、int、long、float、double (JDK1.8)
java.lang.Boolean
1 public static int hashCode(boolean value) { 2 return value ? 1231 : 1237; 3 }
JDK 1.8新增一个hashCode方法,true的hashCode为1231,false的hashCode为1237, why?
https://stackoverflow.com/questions/3912303/boolean-hashcode
1 public static int compare(boolean x, boolean y) { 2 return (x == y) ? 0 : (x ? 1 : -1); 3 }
在类中定义了两个public static final的变量,在创建Boolean对象的时候可以
1 public static final Boolean TRUE = new Boolean(true); 2 public static final Boolean FALSE = new Boolean(false);
在创建Boolean对象的时候整个项目如果都是采用valueOf方法来创建,则整个项目就都会使用的这两个对象了。
1 public static Boolean valueOf(boolean b) { 2 return (b ? TRUE : FALSE); 3 } 4 public static Boolean valueOf(String s) { 5 return parseBoolean(s) ? TRUE : FALSE; 6 }
剩下的Byte、Short、Integer、Long、Float、Double都是继承自Number类,除此之外还有BigDecimal和BigInteger类。
下面总结下基础数据类型的数值范围
数据类型 | 字节 | 范围 |
boolean | 1 | true或false |
char | 2 | 从字符型对应的整型数来划分,其表示范围是0~65535 |
byte | 1 | -128~127 |
short | 2 | -32768~32767 |
int | 4 | -2147483648~2147483647 (-2^31 ~ 2^31-1) |
long | 8 | -9223372036854775808 ~ 9223372036854775807 |
float | 4 | -3.4E38~3.4E38 |
double | 8 | -1.7E308~1.7E308 |
java.lang.Integer
1 public static String toString(int i) { 2 if (i == Integer.MIN_VALUE) 3 return "-2147483648"; 4 int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); 5 char[] buf = new char[size]; 6 getChars(i, size, buf); 7 return new String(buf, true); 8 } 9 10 static void getChars(int i, int index, char[] buf) { 11 int q, r; 12 int charPos = index; 13 char sign = 0; 14 15 if (i < 0) { 16 sign = '-'; 17 i = -i; 18 } 19 20 // Generate two digits per iteration 21 while (i >= 65536) { 22 q = i / 100; 23 // really: r = i - (q * 100); 24 r = i - ((q << 6) + (q << 5) + (q << 2)); 25 i = q; 26 buf [--charPos] = DigitOnes[r]; 27 buf [--charPos] = DigitTens[r]; 28 } 29 30 // Fall thru to fast mode for smaller numbers 31 // assert(i <= 65536, i); 32 for (;;) { 33 q = (i * 52429) >>> (16+3); 34 r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... 35 buf [--charPos] = digits [r]; 36 i = q; 37 if (i == 0) break; 38 } 39 if (sign != 0) { 40 buf [--charPos] = sign; 41 } 42 } 43 44 final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; 45 46 // Requires positive x 47 static int stringSize(int x) { 48 for (int i=0; ; i++) 49 if (x <= sizeTable[i]) 50 return i+1; 51 } 52 53 final static char [] DigitTens = { 54 '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 55 '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', 56 '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', 57 '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', 58 '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', 59 '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', 60 '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', 61 '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', 62 '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', 63 '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', 64 } ; 65 66 final static char [] DigitOnes = { 67 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 68 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 69 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 70 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 71 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 72 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 73 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 74 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 75 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 76 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 77 } ;
感觉这个toString方法实现的太巧妙了,为了减少运算真是无所不用其极,忍不住将这一整段的代码都贴出来了。
stringSize方法是计算整个正整数x有多少个字符,如此就可以预先计算出一个整型转换为字符数组要提前分配多少空间。这个方法的实现是通过比较大小实现的,预先定义好一个从小到大的数组sizeTable,配合下标确定size。
getChars方法是将整型i转换为一个字符数组buf,其中index参数是整型i中包含的字符数,也即buf需要多少长度来存储转换后的整型。在方法中如果整型i >= 65536,则通过q = i/100; r = i - q * 100;的方式将数字拆分成两个部分,其中r为i的前两位。高潮来了,看他怎么实现的获取这两位的字符的,竟然用数组查询的方式!当然,这是个while循环,会一直处理直到i<65536。再看下for循环中的将小于65536的数字转换为字符数组。q = (i * 52429) >>> (16+3) 这一句其实是个除以10的操作,那为什么要用52429呢?524288 = 2^19, i * 52429 然后无符号右移19位,相当于52429/2^19 = 0.100000381,近似是等于i/10(移位运算远比除法快,也是一种优化策略)。那为什么要选择2^19呢?参考了下知乎的回答:java源码中Integer.class中有个getChars方法,里面有个52429是怎么确定的?。然后我又计算了下2^20和2^21,结果竟然等于2^19,然后2^22精度就更高一些,但也没有太大的必要了。
1 private static class IntegerCache { 2 static final int low = -128; 3 static final int high; 4 static final Integer cache[]; 5 6 static { 7 // high value may be configured by property 8 int h = 127; 9 String integerCacheHighPropValue = 10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 11 if (integerCacheHighPropValue != null) { 12 try { 13 int i = parseInt(integerCacheHighPropValue); 14 i = Math.max(i, 127); 15 // Maximum array size is Integer.MAX_VALUE 16 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 17 } catch( NumberFormatException nfe) { 18 // If the property cannot be parsed into an int, ignore it. 19 } 20 } 21 high = h; 22 23 cache = new Integer[(high - low) + 1]; 24 int j = low; 25 for(int k = 0; k < cache.length; k++) 26 cache[k] = new Integer(j++); 27 28 // range [-128, 127] must be interned (JLS7 5.1.7) 29 assert IntegerCache.high >= 127; 30 } 31 32 private IntegerCache() {} 33 } 34 35 public static Integer valueOf(int i) { 36 if (i >= IntegerCache.low && i <= IntegerCache.high) 37 return IntegerCache.cache[i + (-IntegerCache.low)]; 38 return new Integer(i); 39 }
通过IntegerCache内部类将常用的整数存储起来,当使用valueOf的方式构造Integer对象的时候,会直接从IntegerCache中取值。IntegerCache的最小值固定为-128,最大值可以通过java.lang.Integer.IntegerCache.high设置。
java.lang.Byte
在Byte类中同样是有个ByteCache缓存的缓存了从-128到正的127的byte,也就是byte的取值范围都被缓存了。通过下面的valueOf就可以使用到ByteCache类中的缓存值了。
1 public static Byte valueOf(byte b) { 2 final int offset = 128; 3 return ByteCache.cache[(int)b + offset]; 4 }
Byte中的很多函数都是将byte转换成int然后再操作的。
java.lang.Short
Short类中也同样有个ShortCache缓存,缓存了从-128到127的整数,不过要注意short是两个字节的。同样的使用ValueOf可以使用缓存中的内容。
1 private static class ShortCache { 2 private ShortCache(){} 3 4 static final Short cache[] = new Short[-(-128) + 127 + 1]; 5 6 static { 7 for(int i = 0; i < cache.length; i++) 8 cache[i] = new Short((short)(i - 128)); 9 } 10 } 11 12 public static Short valueOf(short s) { 13 final int offset = 128; 14 int sAsInt = s; 15 if (sAsInt >= -128 && sAsInt <= 127) { // must cache 16 return ShortCache.cache[sAsInt + offset]; 17 } 18 return new Short(s); 19 }
1 public static short reverseBytes(short i) { 2 return (short) (((i & 0xFF00) >> 8) | (i << 8)); 3 }
在Short类中还有个reverseBytes函数,将高位字节和低位字节互换位置。不知道这样做有什么用途。
java.lang.Long
同样的在Long类中toString方法实现类似于Integer中的toString方法,不再赘述。
在缓存方面,Long类中同样有个LongCache缓存类,缓存了-128L~127L的Long对象,通过valueOf可以直接获取缓存中的类对象。
在JDK 1.8中,增加了以下几个方法
1 // 比较两个long 2 // @since 1.7 3 public static int compare(long x, long y) { 4 return (x < y) ? -1 : ((x == y) ? 0 : 1); 5 } 6 7 // 比较两个unsigned long 8 // @since 1.8 9 public static int compareUnsigned(long x, long y) { 10 return compare(x + MIN_VALUE, y + MIN_VALUE); 11 } 12 13 // 除法运算,结果是除得的结果,余数采用remainderUnsigned获得 14 // @since 1.8 15 public static long divideUnsigned(long dividend, long divisor) { 16 if (divisor < 0L) { // signed comparison 17 // Answer must be 0 or 1 depending on relative magnitude 18 // of dividend and divisor. 19 return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L; 20 } 21 22 if (dividend > 0) // Both inputs non-negative 23 return dividend/divisor; 24 else { 25 /* 26 * For simple code, leveraging BigInteger. Longer and faster 27 * code written directly in terms of operations on longs is 28 * possible; see "Hacker's Delight" for divide and remainder 29 * algorithms. 30 */ 31 return toUnsignedBigInteger(dividend). 32 divide(toUnsignedBigInteger(divisor)).longValue(); 33 } 34 } 35 36 // 除法运算,结果是余数 37 // @since 1.8 38 public static long remainderUnsigned(long dividend, long divisor) { 39 if (dividend > 0 && divisor > 0) { // signed comparisons 40 return dividend % divisor; 41 } else { 42 if (compareUnsigned(dividend, divisor) < 0) // Avoid explicit check for 0 divisor 43 return dividend; 44 else 45 return toUnsignedBigInteger(dividend). 46 remainder(toUnsignedBigInteger(divisor)).longValue(); 47 } 48 }
另外增加了sum方法,如下面的代码,代码中并没有考虑溢出问题,所以谨慎调用。
1 public static long sum(long a, long b) { 2 return a + b; 3 }
java.lang.Double
1 public boolean equals(Object obj) { 2 return (obj instanceof Double) 3 && (doubleToLongBits(((Double)obj).value) == 4 doubleToLongBits(value)); 5 } 6 7 public static long doubleToLongBits(double value) { 8 long result = doubleToRawLongBits(value); 9 // Check for NaN based on values of bit fields, maximum 10 // exponent and nonzero significand. 11 if ( ((result & DoubleConsts.EXP_BIT_MASK) == 12 DoubleConsts.EXP_BIT_MASK) && 13 (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L) 14 result = 0x7ff8000000000000L; 15 return result; 16 }
在Double类中,重载了equals方法,其中的doubleToRawLongBits是个native方法。
java.lang.Float
Float源码和Double类方法差不多。就这样结束吧。