java中”==”与”equals”的区别
前言
这虽然是一个很基础的话题了,但是很多初学者在网上搜资料与自己跑测试的时候还会出现很多的疑问。下面我就结合这两个的区别以及大家在跑代码时的疑问来深度解析一下。
总的来说
大家应该牢记一点就是:”==”号比较的是内存地址,如果是相同的地址就会返回true,反之false。
“equals”,是对象的方法,所以我们要看一下所有对象的父类Object对象的源码是如何定义这个方法的。
public boolean equals(Object obj) {
return (this == obj);
}
看了源码大家应该就很明白了,在Object这个终极类中,equals方法中还是调用了”==”。
大家再看一下我们常用的String类
public boolean equals(Object anObject) {
如果是同一个对象
if (this == anObject) {
return true;
}
//如果传递进来的参数是String类的实例
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;
//对于每一位置逐一比较
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
源码中体现的也很清楚,它对equals方法进行了重写,重写之后equals方法的作用是比较字符串内容是否相等,如果相等就返回true,不相等返回false
当然对于java中的其他类而言,如果没有重写object类中的equals方法,我们就可以认为与”==”相同,如果重写过equals方法,那么应该按照重写后的定义来判断。
疑问
对于”==”号的疑问
int a= 1;
int b = 1;
Integer A=1;
Integer B=1;
String strA="asd";
String strB="asd";
System.out.println(a==b);
System.out.println(A==B);
System.out.println(strA==strB);
//输出结果
true
true
true
大家可能存在疑问,您不是说”==”号是判断内存地址是否相同的吗?就这测试结果不能令人信服啊。
造成这种情况是因为:缓存。
对于基础类型通过JVM初始化时生成其装箱对象的缓存,然后所有基本类型都被映射到这些缓存对象上,所以做出==相等的假象,因为实际上的确是同一个缓存对象,地址相同。但超过特定值就会失效,超过特定值的基本类型装箱对象是在堆生成,每次都会变动,这样==地址不相同。
对于上面Integer、String等对象类型,出现上面的测试结果是因为在Java中,每次创建对象都要进行内存分配操作,为了减少频繁地创建对象,许多地方采用池来存放对象,如String中的字符串池,对于基本类型,对应的包装类中皆有缓存来避免频繁创建对象如Integer。
Integer A = 1; 其实是一个自动装箱的过程,编译器会自动展开成Integer i = Integer.valueOf(1);详情可以看Integer.valueOf的源代码,可以看到参数的值在IntegerCache.low(默 认-128) 到 IntegerCache.high(默认127)范围内时(比如1),会从IntegerCache.cache中直接取(此处参考Integer的 内部类IntegerCache的源代码,如果不配置的话,默认是cache存储-128到127的Integer),所以取到的都是同一个 Integer的对象,因此相同。如果不在-128到127范围内,所以会new 一个新的Integer,故不相同。
Boolean:(全部缓存)
Byte:(全部缓存)
Character(<= 127缓存)
Short(-128 — 127缓存)
Long(-128 — 127缓存)
Float(没有缓存)
Doulbe(没有缓存)
String 也是同样的道理,创建的流程是,首先括号里的”asd”先到 String pool 里看有没”asd”这个对象,没有
则在 pool 里创建这个对象.所以这里就在 pool 创建了一个”abc”对象.如果存在会被直接指过去。
如何不使用缓存呢?
//明确指出需要创建一个新的对象
Integer A=new Integer(1);
Integer B=new Integer(2);
String strA=new String("asd");
String strB=new String("asd");
//超出Integer缓存池
Integer largeA=200;
Integer largeB=200;
System.out.println(A==B);
System.out.println(largeA==largeB);
System.out.println(strA==strB);
//输出结果
false
false
false
看得到了我们期望的结果啦!