一. 前言
在初学Java的时候,整理过equals和==的详解的教程,但是一直没有时间发布在网站中,今天在学Algs4一书中,又再次遇到了这个问题,干脆将之前的教程整理发布出来
二. 基本数据类型
首先我们来看下两个基本数据类型的比较
public class Equivalence { public static void main(String[] args) { int n1 = 47; int n2 = 47 System.out.println(n1 == n2); } } 输出: true
通过上面的程序我们可以看出,基本数据类型下,值相同,则==返回true ,若值不相同,则返回false
三. 引用数据类型
接下来,我们再看下两个对象的比较
public class Equivalence { public static void main(String[] args) { Integer n1 = new Integer(47); Integer n2 = new Integer(47); System.out.println(n1 == n2); System.out.println(n1.equals(n2)); n1 = n2;//n1的引用被n2的引用覆盖 System.out.println(n1 == n2); System.out.println(n1.equals(n2)); } } 输出: false true true true
n1和n2的值明明都是47,为什么基本数据类型下,n1 == n2 返回的的是true,而对象的比较,返回的却是false呢?
其实是因为n1和n2这两个对象的值虽然相同,但是这两个对象的引用却是不同的,而== 和 != 比较的是对象的引用,所以第一个print输出的是false
四. equals
我们可以利用equals()方法的来比较两个对象的实际内容是否相同:所以第二个print输出的是true
接下来,我们执行n1 = n2; n1的引用被n2的引用覆盖,此时的n1和n2的引用还有值都是相同的
所以第三个第四个输出的都是true
当时整理到这里,以为自己已经理解了equals,其实不然,我们再来看一个例子
class Value { int i; } public class EqualsMethod { public static void main(String[] args) { String s1 = "a"; String s2 = "a"; Value v1 = new Value(); Value v2 = new Value(); v1.i = v2.i = 100; System.out.println(v1.equals(v2)); System.out.println(s1.equals(s2)); } } 输出: false true
我们自己创建了Value类,然后创建两个Value类对象,并赋予相同的值,依旧采用equals方法,返回的却是false了,这是为什么呢?equals不是应该值相同,就返回true吗?这里为什么会是false呢?
我们在eclipse里按住ctrl然后点击equals方法来(按照ctrl,然后把鼠标放在equals方法名上,会出现一个下划线,点进去即可)查看Object.class文件,发现equals方法实现如下:
看到这里便明白了,这是因为equals的默认比较的是引用,所以我们需要重写equals方法,才可以达到预期的效果
那么问题又来了,为什么s1和s2用equals返回的却是true呢?我们同样在eclipse里按住ctrl然后点击si和s2中的equals方法,查看String.class文件
原来string默认重写了equals方法,重写后equals比较的是两个对象的值是否相同.
那么v1和v2既不能用==来判断值是否相同,也不能用默认的equals方法来判断,我们该如何v1和v2比较值是否相等呢?其实很简单,我们模仿String中的重写equals的方法,对equals方法重写就可以了。代码如下:
class Value { int i; @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Value other = (Value) obj; if (i != other.i) return false; return true; } } public class EqualsMethod { public static void main(String[] args) { String s1 = "a"; String s2 = "a"; Value v1 = new Value(); Value v2 = new Value(); v1.i = v2.i = 100; System.out.println(v1.equals(v2)); System.out.println(s1.equals(s2)); } } 输出: true true
现在,v1和v2中的equals方法在我们重写之后,比较的不再是v1和v2的引用,而是他们的值了,我们可以再次按住Ctrl 单击equals方法,发现不再跳转到Object,Class.而是跳转到我们刚才重写的equals方法中
五. 其他知识点
1. 基本数据类型
- boolean——>1
- byte——>1
- char——>2
- short——>2
- int——>4
- long——>8
- Mfloat——>4
- double——>8
2. 引用数据类型
- 类(class)
- 接口(interface)
- 字符串(String)
- 数组([])
- 空类型(null)
3. String 比较
public class Test { public static void main(String[] args) { String s1 = "2"; String s2 = "2"; String s3 = new String("2"); String s4 = new String("2"); System.out.println(s1 == s2 ); //true System.out.println(s1.equals(s2)); //true System.out.println(s3 == s4);//false System.out.println("s2 == s2" + s1 == s2);//false System.out.println("s2 == s2 :" + (s1 == s2));// s2 == s2 :true } }
上面我们已经提到,==在java中是比较的是引用,即在内存中的地址,而String的equals()是比较字符串的内容,所以s1.equals(s2) 结果是true ,这个应该已经没有问题了,但是我们上面也提到了String是引用数据类型,那么 s1 == s2,比较的应该是引用,结果应该是false才对,可为什么结果是true呢?
查阅资料,发现 :
String s1 = “2”;
java首先会在缓冲区查找是否有”String”这个常量对象,有就直接将其地址赋给s1,没有就创建一个”2″,然后将其赋给s1;然后
String s2 = “2”;
java同样会在缓冲区中查找”String”,这次能查找到了,因为s1创建了一个”String”,所以会将其地址赋给s2,如此,s1和s2便有了相同的地址,所以结果是true
但是我们又发现,”s2 == s2″ + s1 == s2 的结果是false,这就奇怪了,s1 == s2 结果不是true吗?为什么这里又变成false了呢?其实这里涉及到运算符优先级的问题, + 优先级比 == 高,所以会先执行 “s2 == s2″ + s1 ,再将其结果 和s2 比较,结果当然是false了,所以需要修成”s2 == s2 :” + (s1 == s2) 这种写法才能得到我们期待的结果
4. 数组比较
public class Test { public static void main(String[] args) { String a[] = new String[2]; a[0] = "2"; a[1] = "2"; int b[] = new int[2]; b[0] = 2; b[1] = 2; System.out.println(a[0] == a[1]);//true System.out.println(b[0] == b[1]);//true System.out.println(args[0] == args[1] ); // args[0]和args[1]都是"2",但结果为false } }
六. 参考资料
Thinking In Java
Algorithms Fourth Edition
请登录之后再进行评论