文章目录
1. 类定义
Integer类定义如下:
public final class Integer extends Number implements Comparable<Integer> {}
-
final修饰
-
继承Number,Number是一个抽象类,Integer重写了其中的方法,这些方法作用就是各种包装类直接的转换(不包括Char)
-
实现Comparable接口,重写compareTo方法,该方法调用了Integer自己的compare方法
public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); }
2. 成员变量
MIN_VALUE=-231
MAX_VALUE=231-1
value:实际存放数据的地方,本质是一个基本类型 int
SIZE:32位
BYTES:4字节
还有像digits、DigitsTens、SizeTable主要是在某些方法中有使用到,用的不多
3. 静态内部类IntegerCache
该类的作用是在程序启动的时候,创建-128~127(可通过设置虚拟机参数-Djava.lang.Integer.IntegerCache.high
来更改)的Integer实例,这样起到一个缓存的作用,下面的自动拆箱装箱例子中,也会有涉及。
4. 构造方法
构造方法有两种:
4.1 传入参数为int
public Integer(int value) {
this.value = value;
}
4.2 传入参数为String
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
parseInt具体代码在下文有分析。parseInt不是自动装箱的方法,valueOf才是!
5. 重要方法
5.1 parseInt
解读看注释。
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) {//要转变成int的字符串s为null,抛出异常
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {//进制radix 小于 最小进制2 ,抛出异常
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {//进制radix 大于 最大进制36 ,抛出异常
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); //获取字符串s的第一个字符,用于判断正负
//这里主要用来判断第一个字符是"+"或者"-",因为这两个字符的 ASCII码都小于字符'0'
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
//如果第一个字符为 - ,标志位negative=true,表示是负数,limit = Integer.MIN_VALUE,数的限制为最小值
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
//如果第一个字符是不是 '+',直接抛出异常
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
//待转换字符长度是1,不能是单独的"+"或者"-",否则抛出异常
throw NumberFormatException.forInputString(s);
i++;//i++也就是定位到第二个字符了,对于第一个字符为 + 的不作处理,按照正数来处理了
}
multmin = limit / radix;
//通过不断循环,将字符串除掉第一个字符之后,根据进制不断相乘在相加得到一个正整数
//parseInt("123",10) = 1*10的2次方+2*10+3*1
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;
}
5.2 toString
有三个重载的toString方法,toString() toString(int i) toString(int i, int radix),关注第二个就可以了
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);
}
主要注意Integer的另外两个方法,stringSize和getChars,其中getChars不做解读了,就是转换成char字符
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;
}
stringSize()它是用来计算参数i的位数也就是转成字符串之后的字符串的长度,内部结合一个已经初始化好的int类型的数组sizeTable来完成这个计算。在stringSize中实现的形式很巧妙。注意负数包含符号位,所以对于负数的位数是stringSize(-i) + 1。
5.3 valueOf
valueOf是自动拆箱的核心,解读看注释。
public static Integer valueOf(int i) {
/*
如果传入参数i在IntegerCache范围内,
就不会实例化一个新的Integer对象,直接返回IntegerCache缓存的对象
否则new一个新的Integer对象
*/
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
5.4 intValue
intValue是自动拆箱的核心。
public int intValue() {
return value;
}
5.5 equals和hashcode
equals方法先判断传入参数是否是Integer类型,是的话拆箱,进行比较
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
hashcode方法直接返回value
public static int hashCode(int value) {
return value;
}
5.6 compare
compareTo 方法内部直接调用 compare 方法:
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
6. 装箱、拆箱
自动装箱拆箱是JDK1.5之后的语法糖,在编译期,根据代码,在生成class文件的时候进行。
-
自动装箱
自动装箱本质就是调用了valueOf,注意valueOf方法有用到IntegerCache。
对于
Integer a = 128;
这段代码,经过反编译工具,可以看到class文件的本质就是Integer a = Integer.valueOf(128);
-
自动拆箱
自动拆箱本质就是调用了intValue。如下自动拆箱例子。
Integer a = new Integer(128); int m = a;
经过反编译工具,可以看到class文件的本质就是
Integer a = new Integer(128); int m = a.intValue();
-
示例
public static void main(String[] args) throws InterruptedException { Integer i = 10; Integer j = 10; System.out.println(i == j);//true Integer a = 128; Integer b = 128; System.out.println(a == b);//false int k = 10; System.out.println(k == i);//true int kk = 128; System.out.println(kk == a);//true Integer m = new Integer(10); Integer n = new Integer(10); System.out.println(m == n);//false }
第一次比较
i == j
,Integer i = 10;
进行了自动装箱,调用valueOf方法,又因为这个方法里面会判断传入参数有没有在IntegerCache的范围内,10在这个返回内,所以并不会创建新的对象,j同理,因此i和j指向的是同一个对象(IntegerCache中已经有的对象),所以第一次比较结果为true第二次比较和第一次同样进行了自动装箱,但因为128超过了IntegerCache的范围,因此会新建一个对象,所以a和b指向的是不同的对象,结果为false
第三次比较
k==i
,k是基本数据类型,这里进行了自动拆箱,也即k==intValue(i)
,这就是比较两个int值,结果为true,第四次同理第五次直接通过new的方式来创建Integer实例,并不会调用自动装箱,也就是没有通过valueOf方法,不会用到IntegerCache的缓存,所有m和n指向不同对象,结果为false
另外,IntegerCache可以通过修改jvm启动参数
Djava.lang.Integer.IntegerCache.high
,来调解缓存,如果改为256,那么第二次比较的结果也会为true,而仔细看了源码之后发现,最少是127String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); //这里取设置的启动参数和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. } }