1.1 前言
Integer是int对应的包装类,它包含一个int类型的字段存储数据,并提供了多个基本操作,能在 int 类型和 String 类型之间互相转换。在Java5中,引入了自动装箱和自动拆箱功能,Java可根据上下文,自动进行转换,极大的简化了相关编程。
1.2 定义
public final class Integer extends Number implements Comparable<Integer>
从上述代码可以看出
- Integer类被final修饰,因此不能被继承。
- Integer类继承了Number类,因此可以调用longValue、floatValue、doubleValue等系列方法返回对应的类型的值。
- Integer类实现了Comparable接口,可以进行比较。
1.3 属性
private final int value;
私有属性,value用于保存int值。
1.4 构造方法
//直接将参数赋值给value属性 public Integer(int value) { this.value = value; } //参数为String类型,调用parseInt(String s,int radix)方法给value赋值,其中radix默认为10,即创建一个十进制的整数 public Integer(String s) throws NumberFormatException { this.value = parseInt(s, 10); }
1.5 核心方法
根据上述第二个构造方法可以知道,当传入一个String类型的参数时,会调用parseInt(String s,int radix)方法,因此接下来我们一起看一下这个方法,源代码如下
public static int parseInt(String s, int radix) throws NumberFormatException { //字符串为空,则报异常 if (s == null) { throw new NumberFormatException("null"); } //其中MIN_RADIX=2,即如果radix<2,抛异常 if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); } //其中MIN_RADIX=36,即如果radix>36,抛异常 if (radix > Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } int result = 0;//最终转换的结果 boolean negative = false;//符号位判断,判断是否是‘-’号,如果是,将negative置为true int i = 0, len = s.length();//设置初始位置和字符串长度 int limit = -Integer.MAX_VALUE;//设置最大边界,MAX_VALUE=2^31-1 int multmin;//最大边界值右移一位 int digit; if (len > 0) {//字符串长度大于0,若小于零则抛出异常 char firstChar = s.charAt(0);//获取字符串第一个字符 if (firstChar < '0') { // 与'0'比较,若小于,则非数字 if (firstChar == '-') {//继续判断是否是'-' negative = true;//如果是,则将negative 设置为true limit = Integer.MIN_VALUE;//将limit设置为MIN_VALUE,其中MIN_VALUE=-2^31 } else if (firstChar != '+') throw NumberFormatException.forInputString(s);//如果首字符既不是‘-’号,又不是‘+’号,则抛异常 if (len == 1) // Cannot have lone "+" or "-" throw NumberFormatException.forInputString(s);//如果首字符只有一个符号,没有数字,则抛出异常 i++;//位置后移一位 } multmin = limit / radix;//用于判断结果是否溢出 //下边的处理逻辑假设,,此时Integer ie = new Integer("324") //首先i=0,取出"3",则digit=3,result = result-digit = -3 //i=1,取出"2",则digit=2,result = result*radix = -3*10 = -30,result = result-digit = -30-2 = -32 //i=2,取出"4",则dight =4,result = -32*10-4 =-324 while (i < len) { // 将字符转换成对应进制的整数 digit = Character.digit(s.charAt(i++),radix); //小于0,抛出异常 if (digit < 0) { throw NumberFormatException.forInputString(s); } //result < multmin==>result<limit/radix==>result * radix<limit 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;//若是负数,则按照上边例子,result = -324,若为正数,则result =-(-324) = 324 }
接下来我们在看看valueOf()方法,Integer提供了三种valueOf方法,源码如下:
//调用parseInt(s,radix),获得一个int值,然后在调用valueOf(int i)方法 public static Integer valueOf(String s, int radix) throws NumberFormatException { return Integer.valueOf(parseInt(s,radix)); } //调用parseInt(s,10),获得一个int值,然后在调用valueOf(int i)方法 public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); } //传入int值位于IntegerCache的成员变量low和high之间时,直接返回IntegerCache.cache[i + (IntegerCache.low)] //否则,新创建一个Integer对象 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
在valueOf(int i)方法中用到了IntegerCache,因此我们在看一下IntegerCache,源码如下:
//IntegerCache是Integer的私有静态内部类 private static class IntegerCache { static final int low = -128;//设置缓存数组元素最小值 static final int high;//设置缓存数组元素最大值 static final Integer cache[];//定义一个Integer类型的数组 static { // high value may be configured by property int h = 127;//设置缓存元素最大值 //读取VM参数 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue);//将配置值转换为int 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. } } high = h; cache = new Integer[(high - low) + 1];//构造缓存数组,大小为256 int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++);//在数组下标为0-255的数组中预先将-128-127存入数组当中 // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
从上述代码可以看出,当调用valueOf方法,如果参数的值在-127到128之间,则直接从缓存中返回一个已经存在的对象。如果参数的值不在这个范围内,则new一个Integer对象返回。
从上边的代码可以得出:parseInt方法返回的是基本类型int;valueOf方法返回Integer对象。
接下来我们再来看看将toString方法,源码如下:
public String toString() { return toString(value); }
public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648";//如果等于Integer.MIN_VALUE,直接返回最小值的字符串形式 //返回一个正整数的位数,当i<0的时候返回的size数组在stringSize方法的基础上+1的目的是这一位用来存储负号 int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size];//创建一个字符数组 getChars(i, size, buf);//得到整数中的每一个字符 return new String(buf, true); }
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
//该方法要求传入一个正整数,假设此时x=1000,那么因为他大于9,99,999,小于9999.所以他会返回9999在整型数组sizeTable中的下标”3″+1 = 4,因此返回一个正整数的位数
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
static void getChars(int i, int index, char[] buf) { int q, r; int charPos = index; char sign = 0; //如果i<0,sign记下它的符号“-”,同时将i转成整数 if (i < 0) { sign = '-'; i = -i; } //当i >= 65536的时候每一次获取两位的char值。 while (i >= 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q << 6) + (q << 5) + (q << 2));//使用移位操作快速计算出q*100,该表达式可以改为i-q*2^6 - q*2^5 - q*2^2= i-64q-32q-4q= i-100q。 i = q; buf [--charPos] = DigitOnes[r];//取数字r%10的结果 buf [--charPos] = DigitTens[r];//取数字r/10的结果 } // 当 i <= 65536的时候每次只获取一位的char值 for (;;) { q = (i * 52429) >>> (16+3);//相当于q=i/10 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;//如果是负数加上符号位 } }
//100以内的数字除以10的结果(取整), //比如取DigitTens[78],返回的是数字7 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', } ; //100以内的数字对10取模的结果, //比如取DigitTens[78],返回的8 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', } ;
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' };
1.6实现Number的方法
源码如下:
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; }
1.7关于Integer的面试题
Integer a = new Integer(127);
Integer b = new Integer(127);
Integer c = new Integer(128);
Integer d = new Integer(128);
Integer e = 128; 反编译过来之后是Integer.valueOf(128)
Integer f = 128; 反编译过来之后是Integer.valueOf(128)
Integer i= 127; 反编译过来之后是Integer.valueOf(127)
Integer j= 127; 反编译过来之后是Integer.valueOf(127)
System.out.println(a==b);//false
System.out.println(a.equals(b));//true
System.out.println(c==d);//false
System.out.println(c.equals(d));//true
System.out.println(e==f);//false
System.out.println(e.equals(f));//true
System.out.println(i==j);//true
System.out.println(i.equals(j));//true