公有常量介绍
/**
*表示int的最小值 - 2^31
*/
@Native public static final int MIN_VALUE = 0x80000000;
/**
*表示int的最大值 2^31 - 1
*/
@Native public static final int MAX_VALUE = 0x7fffffff;
/**
* 表示基本类型int的实例
*/
@SuppressWarnings("unchecked")
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
常用方法的源码分析
toString
public static String toString(int i, int radix)//radix代表进制,用来把i转化为指定进制字符串
public static String toString(int i)//把i转化为十进制字符串
toString(int i, int radix)
的源码如下
/**
* 所有可能用来把数字表示为字符串的字符
*/
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'
};
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)//Character.MIN_RADIX,Character.MAX_RADIX分别为2和36
radix = 10;
/* 如果转化为十进制,则用toString,这个方法更快*/
if (radix == 10) {
return toString(i);
}
char buf[] = new char[33];//由于表示Integer的最小值的二进制需要33位
boolean negative = (i < 0);//判断i是否为负数
int charPos = 32;//记录位置
if (!negative) {
i = -i;
}
/*这段代码通过基数取余,来获取每一位的值,如果看不懂,直接带入十进制来看*/
/*首先:设 i = 123 radix = 10*/
/*第一步:i = -123(上面i=-i) < -10成立,循环开始*/
/*第二步:buf[32] = digits[3] = 3,charPos = 31 digits在上面常量里有*/
/*第三步:i = 123/10 = 12*/
/*重复这一过程*/
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
//见过首位(例如上面123的1)放入数组
buf[charPos] = digits[-i];
if (negative) {//判断是否需要加上 -
buf[--charPos] = '-';
}
//返回结果
return new String(buf, charPos, (33 - charPos));
}
toString(int i)
的源码如下
public static String toString(int i) {
if (i == Integer.MIN_VALUE)//如果等于最小值的话,直接返回
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);//获取i的长度,看下面
char[] buf = new char[size];
getChars(i, size, buf);//将数字i的各位存入数组中
return new String(buf, true);
}
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',
} ;
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;
r = i - ((q << 6) + (q << 5) + (q << 2));//表示 r = i - (q * 100);
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// 当 i < 65536时执行这个
for (;;) {
q = (i * 52429) >>> (16+3);//结果近似于 q = 0.1*i
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;
}
}
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++)//根据与sizeTable中数的比较,得出x的长度
if (x <= sizeTable[i])
return i+1;
}
parseInt
parseInt的源码如下
public static int parseInt(String s, int radix)//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') {
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) {
//获取字符,并转为int
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;
}
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
valueOf
valueOf
的源码如下
public static Integer valueOf(String s, int radix) throws NumberFormatException {//调用valueOf(int i)方法
return Integer.valueOf(parseInt(s,radix));
}
public static Integer valueOf(String s) throws NumberFormatException {//调用valueOf(String s, int radix),且radix默认为10
return Integer.valueOf(parseInt(s, 10));
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)//IntegerCache.low = -128 IntegerCache.high = 127,如果i在这两个数之间,就调用IntegerCache进行缓存
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);//否则之间创建一个Integer
}
构造器
private final int value;
public Integer(int value) {
this.value = value;
}
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
从上面源码可以看出给Integer
赋的值是不可以改变的,由于private final int value;
是常量。但是在编程中 我们可以通过Integer i = 1; i = 3;
直接赋值,这是怎么回事
我们将上面的代码进行反编译,反编译之后的代码如下:
Integer i = new Integer(1);
i = Integer.valueOf(3);
IntegerCache
转载这里
本文将介绍 Java 中 Integer 缓存的相关知识。这是 Java 5 中引入的一个有助于节省内存、提高性能的特性。 首先看一个使用 Integer 的示例代码,展示了 Integer 的缓存行为。接着我们将学习这种实现的原因和目的。 你可以先猜猜下面 Java 程序的输出结果。很明显,这里有一些小陷阱,这也是我们写这篇文章的原因。
/**
* 测试Integer的缓存 IntegerCache.cache
*/
private static void testIntegerCache() {
System.out.println("---int---");
int a = 127, b = 127;
System.out.println(a == b); //true
a = 128;
b = 128;
System.out.println(a == b); //true
System.out.println("---Integer---");
Integer aa = 127, bb = 127;
System.out.println(aa == bb); //true
aa = 128;
bb = 128;
System.out.println(aa == bb); //false
System.out.println(aa.equals(bb)); //true
}
执行结果就如同上面的那样,我就不贴图来展示啦,我把原文的例子给换成自己的了。
在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。 上面的规则适用于整数区间 -128
到 +127
。 这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。 Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法
Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood
现在我们知道了 JDK 源码中对应实现的部分在哪里了。我们来看看 valueOf 的源码。下面是 JDK 1.8.0 build 25 中的代码。
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
在创建新的 Integer 对象之前会先在 IntegerCache.cache (是个Integer类型的数组)中查找。有一个专门的 Java 类来负责 Integer 的缓存。
IntegerCache 类
IntegerCache 是 Integer 类中一个私有的静态类。我们来看看这个类,有比较详细的文档,可以提供我们很多信息。
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
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() {}
}
Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。
实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的。 在程序中第一次使用 Integer 的时候也需要一定的额外时间来初始化这个缓存。
Java 语言规范中的缓存行为
在 Boxing Conversion 部分的Java语言规范(JLS)规定如下: 如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1这个估计是版本号吧),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。
其他缓存的对象 这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。 有 ByteCache 用于缓存 Byte 对象 有 ShortCache 用于缓存 Short 对象 有 LongCache 用于缓存 Long 对象 有 CharacterCache 用于缓存 Character 对象 Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。