1 package cn.galc.test; 2 3 public class TestEquals { 4 public static void main(String[] args) { 5 /** 6 * 这里使用构造方法Cat()在堆内存里面new出了两只猫, 7 * 这两只猫的color,weight,height都是同样的, 8 * 但c1和c2却永远不会相等,这是由于c1和c2分别为堆内存里面两只猫的引用对象, 9 * 里面装着能够找到这两只猫的地址,但因为两只猫在堆内存里面存储在两个不一样的空间里面, 10 * 因此c1和c2分别装着不一样的地址,所以c1和c2永远不会相等。 11 */ 12 Cat c1 = new Cat(1, 1, 1); 13 Cat c2 = new Cat(1, 1, 1); 14 System.out.println("c1==c2的结果是:"+(c1==c2));//false 15 System.out.println("c1.equals(c2)的结果是:"+c1.equals(c2));//false 16 } 17 } 18 19 class Cat { 20 int color, weight, height; 21 22 public Cat(int color, int weight, int height) { 23 this.color = color; 24 this.weight = weight; 25 this.height = height; 26 } 27 }
程序:html
Cat c1 = new Cat(1,1,1);java
Cat c2 = new Cat(1,1,1);api
执行完以后内存之中的布局以下图所示,布局
c1指向一个对象,c2也指向一个对象,c1和c2里面装着的是这两只Cat对象在堆内存里面存储的地址,因为这两只Cat对象分别位于不一样的存储空间,所以c1和c2里面装着的地址确定不相等,所以c1和c2这两个引用对象也确定不相等。所以执行:“System.out.println(c1==c2);”打印出来的结果确定是false。所以你new出来了两个对象,你放心,这两个对象的引用永远不同,同样的话就会把其中一个给覆盖掉了,这个可不成。c1是否是等于c2比较的是c1和c2这两个引用里面装着的内容,由于new出来的两个对象的它们的引用永远不同,所以c1和c2这两个引用的内容也永远不同,所以c1永远不可能等于c2。所以经过比较两个对象的引用是永远没法使得两个对象相等的,如出一辙的。this
要想判断两个对象是否相等,不能经过比较两个对象的引用是否相等,这是永远都得不到相等的结果的,由于两个对象的引用永远不会相等,因此正确的比较方法是直接比较这两个对象,比较这两个对象的实质是否是同样的,即这两个对象里面的内容是否是相同的,经过比较这两个对象的属性值是否相同而决定这两个对象是否相等。spa
Object类提供了一个equals()方法来比较两个对象的内容是否相同,所以咱们能够采用这个方法去比较两个对象是否在逻辑上“相等”。如:c1.equals(c2);这里是调用从Object类继承下来的equals()方法,经过查阅API文档获得Object类里的equals方法的定义以下:code
public boolean equals(Object obj)htm
在Object这个类里面提供的Equals()方法默认的实现是比较当前对象的引用和你要比较的那个引用它们指向的是不是同一个对象,即和“c1==c2”这种写法是同样的,“c1.equals(c2)”与“c1==c2”是彻底等价的。所以直接使用继承下来的equals()方法也是没法直接比较两个对象的内容是否相同的,为此,咱们必须得重写equals()方法,改变这个方法默认的实现。对象
下面在Cat类里面重写这个继承下来的equals()方法:blog
1 class Cat { 2 int color, weight, height; 3 4 public Cat(int color, int weight, int height) { 5 this.color = color; 6 this.weight = weight; 7 this.height = height; 8 } 9 10 /** 11 * 这里是重写相等从Object类继承下来的equals()方法,改变这个方法默认的实现, 12 * 经过咱们本身定义的实现来判断决定两个对象在逻辑上是否相等。 13 * 这里咱们定义若是两只猫的color,weight,height都相同, 14 * 那么咱们就认为这两只猫在逻辑上是如出一辙的,即这两只猫是“相等”的。 15 */ 16 public boolean equals(Object obj){ 17 if (obj==null){ 18 return false; 19 } 20 else{ 21 /** 22 * instanceof是对象运算符。 23 * 对象运算符用来测定一个对象是否属于某个指定类或指定的子类的实例。 24 * 对象运算符是一个组合单词instanceof。 25 * 该运算符是一个双目运算符,其左边的表达式是一个对象,右边的表达式是一个类, 26 * 若是左边的对象是右边的类建立的对象,则运算结果为true,不然为false。 27 */ 28 if (obj instanceof Cat){ 29 Cat c = (Cat)obj; 30 if (c.color==this.color && c.weight==this.weight && c.height==this.height){ 31 return true; 32 } 33 } 34 } 35 return false; 36 } 37 }
此时在再main方法里面执行打印的命令:
1 public static void main(String[] args) { 2 /** 3 * 这里使用构造方法Cat()在堆内存里面new出了两只猫, 4 * 这两只猫的color,weight,height都是同样的, 5 * 但c1和c2却永远不会相等,这是由于c1和c2分别为堆内存里面两只猫的引用对象, 6 * 里面装着能够找到这两只猫的地址,但因为两只猫在堆内存里面存储在两个不一样的空间里面, 7 * 因此c1和c2分别装着不一样的地址,所以c1和c2永远不会相等。 8 */ 9 Cat c1 = new Cat(1, 1, 1); 10 Cat c2 = new Cat(1, 1, 1); 11 System.out.println("c1==c2的结果是:"+(c1==c2));//false 12 System.out.println("c1.equals(c2)的结果是:"+c1.equals(c2));//true 13 }
这一次获得的结果就与上次没有重写equals()方法时获得的结果就不同了:
“System.out.println(c1 == c2);”打印出来的结果依然是false,由于这里是比较两个对象的引用里面的内容,这两个引用里面的内容固然不相等,并且永远不会相等,因此打印出来的结果确定是false。
“System.out.println(c1.equals(c2));”打印出来的结果为true,由于咱们在Cat类里面重写了equals()方法,改变了这个方法默认的实现,咱们把方法的实现改成只要这个两个对象是真的存在,而且都是猫,而且它们的颜色(color),身高(height)和体重(weight)都相同,那么这两只猫在逻辑上就是如出一辙的,是彻底相同的两只猫,即这两只猫是“相等”的。因此这里打印出来的结果是true。
看下面的例子:
1 public class TestEquals { 2 3 public static void main(String args[]){ 4 String s1 = new String("hello"); 5 String s2 = new String("hello"); 6 System.out.println("s1 == s2的结果是:"+(s1 == s2));//false 7 System.out.println("s1.equals(s2)的结果是:"+s1.equals(s2));//true 8 } 9 }
这一次是比较两个字符串对象是否相等:
System.out.println(s1 == s2);
打印出来的结果依然是fase,由于这里比较的是s1和s2两个字符串对象的引用,两个对象的引用永远不会相等,因此打印出来的结果为false。
System.out.println(s1.equals(s2));
打印出来的结果为true,由于在String类里面重写了从Object类继承(全部的类都是从Object类继承下来,String类固然也不例外,从父类继承下来就拥有了父类的一切属性与方法,因此Sting类里面也有equals()方法,而且还把这个继承下来的equals()方法重写了)下来的equals()方法,改变了这个方法默认的实现,
在String类里面是这样重写equals()方法的实现的:用当前的这个字符串对象和指定的字符串对象比较,指定的字符串对象不能为空而且这个对象的字符序列和当前这个字符串对象的字符串序列同样,若是这些条件都知足,那么这两个字符串对象就是相等的。
所以这里的s2已经知足了条件,因此打印出来的结果是true。
之后在某一个类里面比较两个对象是否相等时,首先去API文档里面查找这个类是否重写了从Object类继承下来的equals()方法。若是重写了equals()方法,那么在比较两个对象是否相等时调用的就是重写之后的equals()方法,若是没有重写,那么调用时就是直接调用从Object类里面的继承下来的那个equals()方法,而且采用equals()方法默认的实现去比较两个对象是否相等。所以每个类均可以根据须要对从Object类继承下来的equals()方法进行重写。
对于在API文档里面找某个类,若是一个类不用引入包就能够直接使用,那么这个类确定是在java.lang这个包里面,如这里的String类,直接就可使用了,因此String类必定是在java.lang这个包里面。使用某个类时看这个类引入的是哪一个包,而后就去这个包里面找这个类,不用引入包的类必定是位于java.lang里面,直接去java.lang里面找就能够了。
总结:比较两个对象是否相等,咱们采用equals()方法,判断两个对象是否相等的条件是由咱们重写equals()方法的实现后定义的,这样就能够比较灵活地使用equals()方法在不一样的类里面比较位于同一类下的两个对象是否相等了。