==和equals的区别
==对于基本数据类型来说,是用于比较“值”是否相等的;而对于引用类型来说,是用于比较引用地址是否相同的;而equals则是比较的值是否相同。
代码示例:
String a = "test";
String b = "test";
String c = new String("test");
String d = new String("test");
System.out.println(a==b); //true
System.out.println(a==c); //false
System.out.println(a.equals(b)); //true
System.out.println(a.equals(c)); //true
System.out.println(c==d); //false
System.out.println(c.equals(d)); //true
代码解读:因为a和b指向的是同一个引用,所以==也是true,而new String()方法则重写开辟了内存空间,所以= =结果为false,而equals比较的一直是值,所以结果都为true。
1、==解读
对于基本类型和引用类型==的作用效果是不同的,如下所示:
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用地址是否相同;
字符串常量池
让我们分析下上述的代码:
在我的理解中常量池应该是为了减少开发者对字符串过度的创建,导致内存使用率的提升,
毕竟String类是一个final类,操作字符串永远不会改变当前字符串的值,只会新增一个字符串的对象。
/*
JVM在编译的时候会先查看a字面量test是否存在字符串常量池中有则直接引用字符串常量池里面的地址,没有则在字符串常量池中新建一个
*/
String a = "test";
/*
b发现字符串常量池里面已经有了test则直接把字符串常量池里面的地址拿了过来
*/
String b = "test";
System.out.println(a==b); //true
//最终a和b的地址都是相同的,结果为true。
然而,c和d的比较结果为false呢?
String c = new String("test");
String d = new String("test");
System.out.println(c==d); //false
new String()会在代码运行的时候在堆中开辟一个空间存放引用字符串常量池里面的地址但是栈里面引用的堆的地址是不一样的,所以即使引用的字符串常量池里面的地址是一样的也不可能为true。
intern方法
强制String对象使用字符串常量池
String c = new String("test");
String d = new String("test");
c = c.intern();
d = d.intern();
System.out.println(c==d); //true
2、equals解读
equals本质上就是==,只不过String重写了equals方法,把它变成了值比较。
首先来看默认情况下equals比较一个有相同值的对象,代码如下:
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name) {
this.name = name;
}
public static void main(String[] args) {
User user1 = new User("test");
User user2 = new User("test");
System.out.println(user1.equals(user2)); //false
}
}
查看源码我们可以知道Java中默认的equals方法实现如下:
public boolean equals(Object obj) {
return (this == obj);
}
同样的比较两个相同值的String对象,为什么返回的是true?如下代码:
String test1 = new String("test");
String test2 = new String("test");
System.out.println(test1.equals(test2)); //true
查看源码发现String重写了Object的equals方法,把引用比较改成了值比较,代码如下:
public boolean equals(Object anObject) {
//对象引用相同直接返回true
if (this == anObject) {
return true;
}
//判断需要对比的值是否为String类型,如果不是则直接返回false
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
//把两个字符串都转换成char数组对比
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//循环对比两个字符串的每一个字符
while (n-- != 0) {
//如果其中有一个字符不相等就返回false,否则继续对比
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
总结
- 字符串字面量会在编译时就开始判断是否在字符串常量池里面创建,而new String()会在代码运行的时候才去判断。
- 字符串常量池里面没有此字符串则会创建,有则会去引用字符串常量池里面的字符串。字面量里字符串常量池的地址存放在栈中,new Sring()则存放在堆中。
- Java语言里的equals()方法其实是交给开发者去重写的,让开发者自己去定义满足什么条件的两个Object是equals的。