这个问题看起来比较简单,可以问的问题可多可少。
一般常见的考察范围是java的基础数据类型和包装类。然后可以延伸到自动拆箱和自动装箱以及包装类中的缓存和缓存范围。当然还可以延伸到设计模式–享元模式等。
首先比较典型的回答:
1.由于Integer变量是两个对象的引用,所以new出Integer是两个对象,永远不相等
Integer a = new Integer(2);
Integer b = new Integer(2);
System.out.println(a==b);//false
2.Integer一个被new出来,一个直接赋值。结果也不相等。
Integer a = new Integer(2);
Integer c = 2;
System.out.println(a==c);//false
这是对象c是怎样产生的呢,我们可以通过编译javac和反编译javap -c来查看一下。
public class IntegerTest {
public static void main(String[] args) {
Integer a = new Integer(2);
Integer c = 2;
System.out.println(a==c);
}
}
public class com.zktravel.IntegerTest {
public com.zktravel.IntegerTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":
()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Integer
3: dup
4: iconst_2
5: invokespecial #3 // Method java/lang/Integer.""
:(I)V
8: astore_1
9: iconst_2
10: invokestatic #4 // Method java/lang/Integer.valueOf:
(I)Ljava/lang/Integer;
13: astore_2
14: getstatic #5 // Field java/lang/System.out:Ljava/
io/PrintStream;
17: aload_1
18: aload_2
19: if_acmpne 26
22: iconst_1
23: goto 27
26: iconst_0
27: invokevirtual #6 // Method java/io/PrintStream.printl
n:(Z)V
30: return
}
我们在第10行可以看出,是通过Integer.valueOf实例化的变量。这时我们再看下Integer.valueOf()这个方法。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
可以看出如果int i在缓存中池使用缓存池的对象,如果不在就new一个。
3.如果两个Integer都是非new出来的进行比较时,如果两个变量的值在-128到127之间,两个值相等。如果不在-128到127之间,则不相等。
public static void main(String[] args) {
Integer a = 2;
Integer c = 2;
System.out.println(a==c);//true
Integer b = 128;
Integer d = 128;
System.out.println(b==d);//false
}
由上面Integer.valueOf可以如果不在缓存范围内就会new Integer。所有b和d不相等。
4.如果是Integer变量与int变量比较时,只要两个变量的值相等,就相等。因为包装类Integer与基础类型int比较时,包装类会自动拆箱为int,然后进行比较。最后就是两个int变量的比较了。
public static void main(String[] args) {
Integer a = 2;
int c = 2;
System.out.println(a==c);//true
Integer b = 128;
int d = 128;
System.out.println(b==d);//true
}
通过javac编译和javap -c反编译后可以看到:
public com.zktravel.IntegerTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":
()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_2
1: invokestatic #2 // Method java/lang/Integer.valueOf:
(I)Ljava/lang/Integer;
4: astore_1
5: iconst_2
6: istore_2
7: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;
10: aload_1
11: invokevirtual #4 // Method java/lang/Integer.intValue
:()I
14: iload_2
15: if_icmpne 22
18: iconst_1
19: goto 23
22: iconst_0
23: invokevirtual #5 // Method java/io/PrintStream.printl
n:(Z)V
26: sipush 128
29: invokestatic #2 // Method java/lang/Integer.valueOf:
(I)Ljava/lang/Integer;
32: astore_3
33: sipush 128
36: istore 4
38: getstatic #3 // Field java/lang/System.out:Ljava/
io/PrintStream;
41: aload_3
42: invokevirtual #4 // Method java/lang/Integer.intValue
:()I
45: iload 4
47: if_icmpne 54
50: iconst_1
51: goto 55
54: iconst_0
55: invokevirtual #5 // Method java/io/PrintStream.printl
n:(Z)V
58: return
Integer变量先通过Integer.valueOf初始化,然后再通过Integer.intValue拆箱转化为int。
下面再通过Integer的源码再看一下。
public final class Integer extends Number implements Comparable<Integer> {}
上面用到Integer.valueOf(),先判断传入的值是否在缓存范围内,如果在缓存范围内(默认-128到127),则指向缓存池中的对像,如果不在就new一个。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
默认的最低是-128,最大是127.
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() {}
}
当然这里可以通过设置jvm启动值改变最大值size。
-XX:AutoBoxCacheMax=size
Integer提供了两个构造方法:
//构造一个新分配的 Integer 对象,它表示指定的 int 值。
public Integer(int value) {
this.value = value;
}
//构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
其中parseInt方法第一个参数是值,第二个是基数,默认是10进制。
其他还可能是16进制,2进制,8进制等。
Integer还提供了valueof转化String为Integer的方法。同样是先使用parseInt()先进行转换,然后再使用Integer.valueOf进行转换(默认使用10进制)。如下:
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
Integer提供的toString方法比较简单。但是里面的实现方式很值得学习。
public static String toString(int i) {
//这里先对i的值做检验,如果等于Int能表示的最小值,则直接返回最小值的字符串形式
if (i == Integer.MIN_VALUE)
//这里直接返回最小值,因为下面的方法最大只能返回2147483647
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);
}
通过stringsize()可以了解第一步先返回最小值的原因。
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;
}
因为如果是负数,需要先转化为整数,进行+1传入。多的一位用了存储负号。整数的最大值只有2147483647。
sizeTable为数组,设置了范围。基于范围的查找,性能上有优势。
getChars()主要是进行了移位和乘法操作。
最后使用string构造函数返回String.