转载 http://blog.csdn.net/u013054285/article/details/78985798
1.equals()和==是什么?
equals():是方法,定义在超类Object中的一个方法,用来比较两个对象。
==:是操作符,用来比较两个对象。
为什么会将一个操作符和一个方法进行比较呢?
因为它们都是用来比较两个对象的,但它们在用法上又有些区别。
这些区别如果不稍加注意,在开发的过程中就很容易翻车。
个人理解:
==和equals()作用是相同的。
但是equals()是一个方法,可以重写equals()方法,实现不同的作用。比如String类中的eqauls()方法。
2.为什么说它们是一样的?
我们来看一下Object中是如何实现eqauls()方法,代码如下:
public boolean equals(Object obj) {
return (this == obj);
}
很明显,在源代码中,equals()方法返回的就是使用 == 比较两个对象后的结果。
从这个角度来说,我认为它们的作用是一样的,都是用来比较两个对象的引用的。
3.它们的区别在哪?
最直观的来看,==是操作符,eqauls()是超类Object中的方法,这是最基本的区别。
正是由于这个区别,才有了== 和eqauls()的不同用法。
首先,eqauls()方法是超类Object中的方法,而Java中所有的对象都是继承自Object类的,所以子类是可以重写eqauls()方法而实现不同的功能。
最典型的就是String类中的equals()方法,代码如下:
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重写了equals()方法,从引用地址比较变成引用内容的比较。
4.栗子
4.1.第一个栗子:
我们先来比较下基本数据类型:
public static void main(String[] args) {
int a = 3;
int b = 3;
System.out.println(a == b);
}
console:
true
对8种基本数据类型使用==比较。
Tips:首先基本数据类型不是对象,也就不是Object类的子类了,所以没有equals()方法。
但是这好像又违反了Java的“一切都是对象”的准则,所以,Java就给基本数据类型提供了包装类型。
4.2.第二个栗子:
我们来比较下String类型:
public static void main(String[] args) {
String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
String str3 = "abc";
System.out.println(str1 == str3);
System.out.println(str1.equals(str3));
}
console:
false
true
true
true
String类型为什么会产生这种结果呢?
首先我们来了解String的两种创建方式:
- 使用引号创建:创建的对象会存放在字符串缓冲池中。当创建str1时,JVM会在字符串缓冲池中寻找”abc”,没有找到,则创建”abc”,然后将str1指向”abc”。创建str2的过程和创建str1是一样的,只不过此时字符串缓冲池中包含了”abc”,则直接将str2指向”abc”。
- 使用new创建:使用new来创建对象,存放在堆中,而且每次都会重新创建一个对象。
再结合我们对 == 和equals()的分析,以及String类对equals()的重写,我们很容易就会明白为什么会是这种结果了。
Tips: String类提供了一个intern()的方法。如果对str2使用intern()方法,代码如下:
public static void main(String[] args) {
String str1 = "abc";
String str2 = new String("abc");
str2 = str2.intern();
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
}
console:
true
true
为什么会产生这种结果呢?我们来看下官方是怎么说的。
在String类的源码中,我们找到intern()方法,官方提供了一段注释,其中有一段是这么写的
/* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
*/
大概意思就是说:调用intern()方法的时候,会首先查找缓冲池中是否有这个字符串,如果有,直接返回;如果没有,则在缓冲池中创建这个字符串,然后返回对象的引用。
4.3.第三个栗子:
我们首先定义一个Cat类
public class Cat {
}
然后我们在方法中进行比较:
public static void main(String[] args) {
Cat cat1 = new Cat();
Cat cat2 = new Cat();
System.out.println(cat1 == cat2);
System.out.println(cat1.equals(cat2));
Cat cat3 = cat1;
System.out.println(cat1 == cat3);
System.out.println(cat1.equals(cat3));
}
console:
false
false
true
true
首先我们创建了cat1对象,并在堆中为其分配了一块地址,而cat1存储的是指向这块地址的引用。
然后我们创建了cat2对象,和cat1一样,在堆中分配了一块地址,然后cat2存储了指向这块地址的引用。
这样,我们在堆中有了两个Cat类的实例对象。而根据==和equals()的规则,cat1和cat2的比较自然不相同。
在创建cat3的时候,我们直接将cat1赋值给了cat3,则cat3中也是存储了和cat1一样的地址。
5.什么时候用?
==:通常我们用在基础数据类型的比较上,因为基础类型的特殊性,所以可以直接使用==来比较基础数据类型的值。同时我们也可以用来比较两个对象是不是同一个对象。
equasl():我们通常用来比较两个对象,或者用来比较String对象的内容。更重要的是,如果有特殊的业务需求,我们可以重写equasl()方法,来实现我们的目的。
6.结语
在equals()和==的比较中,其实涉及到很多JVM内存的知识。关于内存的问题,我会在后期专门写出来和大家分享的。
关于equals()和==的比较,我已经简单的说完了,但是由于个人水平有限,其中难免会出现不够严谨和错误的地方,希望大家不吝赐教。