面了很多家公司,总有几家公司一开口就问“你知道equals()与 == 有啥区别吗”,所以在此写文章记录下来。
学生时代刚学java的时候,常因为String类型的比较使用的是==导致oj无法通过,最后发现要用equals,简直想给自己一巴掌。String类型值比较一定要用equals啊!!
结论
==:
1.基本类型(boolean,byte,short,char,int,float,long,double,)的比较就是值是否相同
2.引用类型的比较就是地址值是否相同
equals:
默认情况下比较的是地址,但很多数类都对它进行了重写可以进行值的比较。
来源
==是运算符,equals是Object类中定义的一个方法
例子
==与equals的简单使用比较
public class equalsORequals {
public static void main(String args[]){
int a = 1;
int b = 1;
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println("a==b is "+(a==b));
//int不能使用equals
// System.out.println("a.equals(a) is " a.equals(b));
System.out.println("str1==str2 is " +(str1 == str2));
System.out.println("str1.equals(str2) is " +(str1.equals(str2)));
}
}
我们可以看一下String中equals的源码,它是对取出的String进行字符的一一比较。
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(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;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
深入了解String中使用==
这里给出一个经典的例题代码
class StringEqualTest {
public static void main(String[] args) {
String s1 = "StringTest";
String s2 = new String("StringTest");
String s3 = "String";
String s4 = "Test";
String s5 = "String" + "Test";
String s6 = s3 + s4;
System.out.println(s1 == s2); //false
System.out.println(s1 == s5); //true
System.out.println(s1 == s6); //false
System.out.println(s1 == s6.intern()); //true
System.out.println(s2 == s2.intern()); //false
}
}
首先我们要明白如果单独使用String s2 = new String("StringTest");这个过程创建了两个对象,首先是new一个对象代表的s2存在堆区中,然后在常量池中创建了一个字面量是"test"。
在本例子中s1已经创建常量池对象,那么s2创建过程中就不会再在常量池中创建。
1.s1==s2(false),==比较的是内存地址,而s2是new出来的新对象在堆中(该新对象也是指向常量池中的“StringTest”的),s1指向的是常量池中的“StringTest”。一个在堆中,一个在常量池肯定不一样。
2.s1==s5(true),字符串+的本质是创建了StringBulider对象进行append操作,然后将拼接后的StringBulider对象用toString进行处理,处理后生成的字符串放在字符串池中找有没有相同值的字符串,如果有将引用(s5)直接连接到已有的字符串地址,所以s1和s5的地址相同
3.s1 == s6(false),因为s6是通过运行时拼接生成的新对象,存储在堆内存中,而s1指向常量池中的对象。请重新解释一下我不太懂
4.s1 == s6.intern()
(true),因为s6.intern()
会返回字符串在常量池中的引用,所以与s1
指向的对象相同。
5.s2 == s2.intern()
(false),因为new String("StringTest")
会在堆中创建一个新的字符串对象,而intern()
方法会检查常量池中是否存在相同值的字符串,如果存在则返回常量池中的引用,否则将其加入常量池并返回引用,但在这里常量池中已经存在了一个相同值的字符串对象,所以不会返回s2
所指向的堆中的对象。
intern()
在Java中,intern()
方法是 String 类的一个方法,它的作用是:
- 如果常量池中已经存在该字符串(与调用 intern() 的字符串内容相同),则返回常量池中该字符串的引用。
- 如果常量池中不存在该字符串,则将该字符串添加到常量池中,并返回常量池中该字符串的引用。
使用 intern()
方法可以确保相同内容的字符串在内存中只存在一份,从而节省内存空间,并且可以用于比较字符串的引用是否相同。