经典面试题:Integer类型 ==比较问题
在聊到面试题之前,需要先搞清楚几个概念。
1、自动装箱与自动拆箱
自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间的一个转化。如int转化为Integer,long转化为Long等。而自动拆箱则相反,是对象包装类型转化成基本数据类型。
Integer num = 2;
num 是Integer类型,而2是int类型,Integer与int并无继承关系,理论上应报错,但因为自动装箱机制存在,Java自动将int转化为Integer类型,即
Integer num = Integer.valueOf(2);
valueOf()方法返回一个Integer类型值,并将其赋值给变量num。这就是int的自动装箱。
2、8种基本数据类型
8种基本数据类型.png3、Integer与int 区别
- Integer是包装类,int是基本数据类型;
- Integer变量必须实例化后才能使用,int不需要;
- Integer实际上是个对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象,而int是直接存储数据值;
- Integer的默认值为null,int的默认值为0。
4、字节字符区别
字节是存储容量的基本单位,字符是数字,字母,汉字以及其他语言的各种符号。 1 字节=8 个二进制单位:一个一个字符由一个字节或多个字节的二进制单位组成。
5、java 基本类型与引用类型的区别
- 基本类型保存原始值。
- 引用类型保存的是引用值(引用值就是指对象在堆中所 处的位置/地址)。
6、常见面试题
- 例1
-
short s1 = 1; s1 = s1 + 1;
首先s1+1运算时会自动提升表达式的类型为int,再将int类型赋值给short类型的s1,会报类型转化错误。 -
short s1 = 1; s1+=1;
+=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
- 例2
Integer a = new Integer(50);
Integer b = new Integer(50);
System.out.print( a == b );
输出为false。
由于Integer变量是对Integer对象的引用,所以两个通过new生成的Integer对象永远是不相等的。
- 例3
Integer c = new Integer(100);
int d = 100;
System.out.print( c == d );
输出为true。
Integer变量与int比较时,只要值相等,则结果为true。因为包装类Integer与int比较时,会自动拆箱为int,然后进行比较,故而最后变成了两个int变量在比较。
- 例4
Integer e = new Integer(100);
Integer f = 100;
System.out.print( e == f );
输出为false。
非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向的是堆中新建的对象,两者的内存地址不同。
- 例5
Integer g = 100;
Integer h= 100;
System.out.print( g == h );
Integer j = 128;
Integer k = 128;
System.out.print( j == k );
第一个输出的是true,第二个是false。
两个非new出来的Integer对象,如果范围在-127~128之间,则为true,否则为false。
Integer g =100。通过自动装箱机制转化为Integer g = Integer.valueOf(100)。
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);
}
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() {}
}
整个工作过程就是:Integer.class在装载(Java虚拟机启动)时,其内部类型IntegerCache的static块即开始执行,实例化并暂存数值在-128到127之间的Integer类型对象。当自动装箱int型值在-128到127之间时,即直接返回IntegerCache中暂存的Integer类型对象。
为什么Java这么设计?
出于效率考虑,因为自动装箱经常遇到,尤其是小数值的自动装箱;而如果每次自动装箱都触发new,在堆中分配内存,就显得太慢了;所以不如预先将那些常用的值提前生成好,自动装箱时直接拿出来返回。哪些值是常用的?就是-128到127了。
比较数值是否相等,而非判断是否为同一对象;而自动装箱又不能保证同一数值的Integer一定是同一对象或一定不是同一对象,那么就不要用==,直接用equals()好了。实际上,Integer重写了equals()方法,直接比较对象的数值是否相等。