概述
简要的介绍了JDK源码中,包装类Integer类的几个常用细节点,以加深对其内部原理的认识。夯实读者Java基础知识。
分析
基础信息介绍
- Integer类中支持的进制数最小为2,最大为36
- Integer类能够表示的最大数值为-2^31,最大数值为(2^31) - 1
- Integer类内部使用了缓存机制,默认缓存-128 ~ 127 之间的数值
详细分析
- 继承 Number 实现 Comparable
从数值型转换为对应的字符串
public static String toString(int i, int radix) { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) radix = 10; /* Use the faster version */ if (radix == 10) { return toString(i); } 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)); } public static String toUnsignedString(int i, int radix) { return Long.toUnsignedString(toUnsignedLong(i), radix); } // 利用Long对象的无符号方法 public static String toHexString(int i) { return toUnsignedString0(i, 4); } // 十六进制 public static String toOctalString(int i) { return toUnsignedString0(i, 3); } // 八进制 public static String toBinaryString(int i) { return toUnsignedString0(i, 1); } // 二进制 /** * Convert the integer to an unsigned number. */ private static String toUnsignedString0(int val, int shift) { // assert shift > 0 && shift <=5 : "Illegal shift value"; int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); int chars = Math.max(((mag + (shift - 1)) / shift), 1); char[] buf = new char[chars]; formatUnsignedInt(val, shift, buf, 0, chars); // Use special constructor which takes over "buf". return new String(buf, true); } 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); } // 有符号的十进制
其中,radix表示转换为对应进制的字符串形式。
解析字符串到对应的数值型(int形式)
public static int parseInt(String s, int radix) throws NumberFormatException { /* * WARNING: This method may be invoked early during VM initialization * before IntegerCache is initialized. Care must be taken to not use * the valueOf method. */ if (s == null) { throw new NumberFormatException("null"); } if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); } if (radix > Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } int result = 0; boolean negative = false; int i = 0, len = s.length(); int limit = -Integer.MAX_VALUE; int multmin; int digit; if (len > 0) { char firstChar = s.charAt(0); if (firstChar < '0') { // Possible leading "+" or "-" if (firstChar == '-') { negative = true; limit = Integer.MIN_VALUE; } else if (firstChar != '+') throw NumberFormatException.forInputString(s); if (len == 1) // Cannot have lone "+" or "-" throw NumberFormatException.forInputString(s); i++; } multmin = limit / radix; 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; } } else { throw NumberFormatException.forInputString(s); } return negative ? result : -result; } 例如: * parseInt("0", 10) returns 0 * parseInt("473", 10) returns 473 * parseInt("+42", 10) returns 42 * parseInt("-0", 10) returns 0 * parseInt("-FF", 16) returns -255 * parseInt("1100110", 2) returns 102 * parseInt("2147483647", 10) returns 2147483647 * parseInt("-2147483648", 10) returns -2147483648 * parseInt("2147483648", 10) throws a NumberFormatException * parseInt("99", 8) throws a NumberFormatException * parseInt("Kona", 10) throws a NumberFormatException * parseInt("Kona", 27) returns 411787 public static int parseUnsignedInt(String s, int radix) throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } int len = s.length(); if (len > 0) { char firstChar = s.charAt(0); if (firstChar == '-') { throw new NumberFormatException(String.format("Illegal leading minus sign " + "on unsigned string %s.", s)); } else { if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits return parseInt(s, radix); } else { long ell = Long.parseLong(s, radix); if ((ell & 0xffff_ffff_0000_0000L) == 0) { return (int) ell; } else { throw new NumberFormatException(String.format("String value %s exceeds " + "range of unsigned int.", s)); } } } } else { throw NumberFormatException.forInputString(s); } } // 无符号字符串到对应的数值
这种形式获得数值是基础类型int形式
- 解析字符串到对应的数值型包装对象(Integer包装对象形式)
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
此种形式下,其内部原理也是先由字符串形式转换为对应基础型int数值,然后再通过装箱为Integer对象 - 数值型装箱到对应的包装对象(具体装箱细节)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
从中可知里面运用了缓存机制,默认对于low和high之间的数值会之间使用缓存数据,没有缓存时创建新对象,其他范围的都是创建新对象。 Integer的缓存原理
Integer类的里面定义了一个私有的静态内部类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); 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.MAX_VALUE - (-low) -1,即:2^31 - 130
具体属性处理类是sun.misc.VM class。Integer对象转换为short、long、float和double等基础类型
public byte byteValue() { return (byte)value; } public short shortValue() { return (short)value; } public int intValue() { return value; } public long longValue() { return (long)value; } public float floatValue() { return (float)value; } public double doubleValue() { return (double)value; } public String toString() { return toString(value); }
Integer的hashCode即为本身数值
public int hashCode() { return Integer.hashCode(value); } public static int hashCode(int value) { return value; }
内容相等性判断
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
并不是比较引用,而是比较内容数值是否相等
比较性处理
public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } /** * Compares two {@code int} values numerically. * The value returned is identical to what would be returned by: * <pre> * Integer.valueOf(x).compareTo(Integer.valueOf(y)) * </pre> * * @param x the first {@code int} to compare * @param y the second {@code int} to compare * @return the value {@code 0} if {@code x == y}; * a value less than {@code 0} if {@code x < y}; and * a value greater than {@code 0} if {@code x > y} * @since 1.7 */ public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } /** * Compares two {@code int} values numerically treating the values * as unsigned. * * @param x the first {@code int} to compare * @param y the second {@code int} to compare * @return the value {@code 0} if {@code x == y}; a value less * than {@code 0} if {@code x < y} as unsigned values; and * a value greater than {@code 0} if {@code x > y} as * unsigned values * @since 1.8 */ public static int compareUnsigned(int x, int y) { return compare(x + MIN_VALUE, y + MIN_VALUE); }
数值相等为0,第一个参数大于第二个参数则为1,第一个参数小于第二个参数为-1
与Long包装类的不同点
- Long的数值范围为-2^63 ~ 2^63-1
- Long中只能缓存-128到127之间的数值
- Long中的hashCode为:(int)(value ^ (value >>> 32))
与Double不同点
- Double 的hashCode计算不同
- Double 中没有缓存机制
与Short不同点 (特殊的共同点hashCode计算方式一样,为自身数值,其他函数用法相同)
- Short中只能缓存-128到127之间的数值
- Short范围-2^15 ~ 2^15 - 1
总结
- 简单的数值包装类,里面涉及很多细节,不容忽视,也是出错点,特别是缓存那里
- 内部的缓存机制,值得借鉴,对于处理内存缓存机制
- 所有的处理都是非线程安全的,容易出问题
- 包装类区别于基础类型,默认未初始化时为null,而不是0