有趣的Java之包装类型的缓存与"==" equals


在进入正文之前 , 我们写来看一段代码

public static void main(String[] args) {
Integer i1 = 127;
Integer i2 = 127;
Integer i3 = new Integer(127);
System.out.println("one==:" + i1 == i2);
System.out.println("one2==:" + i1 == i3);
System.out.println("twoeq:"+i1.equals(i3));
System.out.println("threq:"+i1.equals(i2));
i1 = 128;
i2 = 128;
System.out.println("four==:" + i1 == i2);
System.out.println("fiveq:" + i1.equals(i2));
}

分析这段代码 , 按照我们原来的想法 , 由于在比较对象为基本数据类型时 , “==”比较的是值是否相等 , 但是 Integer 是 int 的包装类 , 它是一个对象 , 所以 “==” 在这里和 equals 一样比较的是对象的引用是否相同 .
粗略一看 , 好像他们的输出应该全为 false , 因为它们都创建了新的对象 .
的确 , 如果是其他对象的话 , 我们的猜想是没有错的 , 但是包装类型不一样 .
equals 在 包装类型和 String 类中被重写了 , 比较的是值是否相等
Object equals 方法实现如下:

public boolean eqauls(Object obj){
return (this == obj);
}

在包装类型中重写 :

public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}

可以看到 , java 将 Object 帮我们转换成了 Integer(对应包装类) , 然后通过 Integer.intValue() 与 value(其值)使用 “==” 进行比较 , 结果自然而然是 true

接下来我们看看equals 在 String 中的重写

 public boolean equals(Object anObject) {
//如果引用相等
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//将 value 和 与之相比的 value 值拆分为 char 一一比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

因此我们对最开始的那段程序有了新的结论 , 他的输出应该是

one==:false
one2==:false
twoeq:true
threq:true
four==:false
fiveq:true

如果这个时候你心满意足 , 那恭喜你得不到正确答案了

包装类型除了重写了 equals , 在后台还为我们做了一件事情 – 缓存 !
java 为了节省内存,设计了基本数据类型包装类的缓存,就是程序启动时,初始化的数值依次放在缓存池中,当你直接给 Integer 对象赋值时,它每次首先去缓存去查,如果有的话,直接将新 new 出的对象引用指向缓存池中的对象 ;
当然缓存池也不是无限大的 , Integer 缓存的范围是[-128,127],超出范围就需要重新在堆内存中new了,Byte 和 boolean 将全部缓存
所以我们运行最开始的程序的时候会发现 , 当 i1 , i2 为 128 时 , 输出的是 false
终于真相大白了 , 所以它最后的输出应该是 :

one==:true //缓存
one2==:false // i3 为新建对象 new Integer(127);
twoeq:true
threq:true
four==:false //超出缓存
fiveq:true

PS : java 虽然没有对 String 做缓存 , 但是可以用 String.intern() 实现同样效果

关注微信公众号

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com