写在前面
学习很难,克服惰性。每天学一点,不会的就少一点。
懦夫从不启程,弱者死于路中,只剩我们前行,一步都不能停。
养成习惯很重要,先从点赞开始吧!关注[程序员之道],程序员之路不再迷茫!
擦,这两个值明明应该是相等的啊,为啥我用==判断的结果时不等于,真是活见鬼了。我来debug看看。关于对象、值一些相等的判断不知道你有没有踩过坑,或者面试的时候有没有被面试官坑过?我就被头条面试官坑过。相等判断几连问,直接晕倒。
如果你还没注意过这些问题,那好好看看下面的内容吧。
使用java编程时,经常写一些判断相等的代码,应该使用==还是equals呢?
但是在实际使用的时候,因为java jvm帮我们做了一些cache的优化,还是有一些坑点的,以下几个问题都可以回答对吗?
public static void main(String[] args) {
boolean result;
Integer a = 99;
Integer b = 99;
result = a == b;
System.out.println("Interger a = 99 is == Interger b = 99:" + result);
Integer c = 128;
Integer d = 128;
result = c == d;
System.out.println("Interger c = 128 is == Interger d = 128:" + result);
Integer e = 99;
Integer f = new Integer(99);
result = e == f;
System.out.println("Interger e = 99 is == Interger f = new Integer(99):" + result);
Integer g = 128;
Integer h = new Integer(128);
result = g == h;
System.out.println("Interger g = 128 is == Interger h = new Integer(128):" + result);
Integer i = new Integer(99);
Integer j = new Integer(99);
result = i == j;
System.out.println("Interger i = new Integer(99) is == j = new Integer(99):" + result);
Integer k = 128;
int l = 128;
result = k == l;
System.out.println("Integer k = 128 is == int l = 128:" + result);
}
}
大家简单的在脑子里过一下程序,不知道这几个例子你都能回答对吗?
先来看下运行结果:
Interger a = 99 is == Interger b = 99:true
Interger c = 128 is == Interger d = 128:false
Interger e = 99 is == Interger f = new Integer(99):false
Interger g = 128 is == Interger h = new Integer(128):false
Interger i = new Integer(99) is == j = new Integer(99):false
Integer k = 128 is == int l = 128:true
Process finished with exit code 0
首先,对于Integer a = 99的这种直接赋值,jvm会编译优化成Interger.valueOf(99),而对于-128~127之间的值,对于Integer类型,为了优化内存使用,jvm对于这个范围内的值,初始化了内存cache,也可以加快访问速度,防止重复建立对象,可以看一下java的源码是怎么实现valueOf的:
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
默认cache的区间是-128~127,也可以自定义cache的high区间。
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() {}
}
知道了这些,我们来分析下刚才的几个例子运行结果为什么是那样的?首先明确,==比较的是地址,而非地址的内容,其次有IntegerCache在搞怪。
所以对于对象相等的比较请使用equals,而非==,==是用于值比较的。
在我们的平时开发中,也要注意类中有用到Integer声明的变量,比较相等时,一定要使用equals,如果使用==比较,可能会出现莫名其妙的错误(-128~127之间的比较正常,其他值的比较就不符合预期了)。
对于使用==判断对象相等,Intellij的插件也会提示我们应该使用equals。
String是对象,那判断相等的方式肯定是使用equal了。但如果用==判断会有什么后果呢?这里也一起看一下。
public static void stringEqual() {
boolean result;
String a = "this";
String b = "this";
result = a == b;
System.out.println("String a = this is == String b = this:" + result);
String c = new String("is");
String d = new String("is");
result = c == d;
System.out.println("String c = new String(is) is == String d = new String(is):" + result);
String e = new String("a").intern();
String f = new String("a").intern();
result = e == f;
System.out.println("String e = new String(a).intern() is == String f = new String(a).intern():" + result);
String g = new String("test");
String h = new String("test");
result = g.equals(h);
System.out.println("String g = new String(test) is == String h = new String(test):" + result);
}
public static void main(String[] args) {
stringEqual();
}
先看下运行结果:
String a = this is == String b = this:true
String c = new String(is) is == String d = new String(is):false
String e = new String(a).intern() is == String f = new String(a).intern():true
String g = new String(test) is == String h = new String(test):true
Process finished with exit code 0
String类的设计,也借鉴了Integer的cache缓存,java的设计之初就是为了节省内存的,所以String对象也是有常量池的。
解释一下刚才几个例子的运行结果:
写在后面
关于equals到这里还没有完,java是如何判断两个对象的equals,set是怎么去重的?砥砺前行,永不停止,我们下篇见!
坚持和习惯是学习中的两大绊脚石,先从养成点赞和评论开始吧,!