java中”==”和equals的关系自己一直没有完全搞清楚,最近把这块好好学习了下,写写自己的心得。
1、”==”
”==”是java中比较运算符的一种,它既可以用来比较数值型数据(包括char型),也可以用来比较引用类型。
”==”用来比较数值型数据这里就不赘述了。介绍下比较引用类型。
(a)
如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,而且这两个引用须指向同一个对象才会返回true。
String str1 = new String("lqf");
String str2 = new String("lqf");
System.out,println(str1==str2);//false
这里定义了两个字符串类型的对象,这两个对象是存在堆内存中的。str1、str2是引用类型变量,它们是存放在栈内存中。str1,str2中存放的是对应对象在堆内存中的地址,他们指向的是不同对象。而new出来的两个对象在堆内存中的地址是不一样的,所以str1==str2输出结果是false。
(b)
//采用这种方式定义字符串,系统会将“我爱java”存到常量池中,s1直接引用
String s1 ="我爱java";
String s2 = "我爱";
String s3 = "java";
//s4后面的字符串在编译阶段就可以确定下来即“我爱java”,
//恰好,常量池中已经保存了“我爱java”,所以s4会直接引用常量池中的“我爱java”。
String s4 = "我爱"+"java";
//s5所代表的字符串在编译阶段是不能确定的,所以不能引用常量池中的“我爱java”
String s5 = s1+s2;
//这里先判断常量池中是否有“我爱java”,没有就创建一个,如果有就在new String()时,将“我爱java”对象复制一份到堆内存中,new一次就复制一个,s6引用String类对象在堆内存中的地址。
String s6 = new String("我爱java");
System.out,println(s1==s4);//true
System.out,println(s1==s5);//false
System.out,println(s1==s6);//false
由于s1和s4都直接引用常量池中的“我爱java”,它们的值都指向同一个内存,所以s1==s4(true)。s5的值在编译阶段不能确定,不能引用常量池中的“我爱java”,s1和s5指向不同的内存,地址不同,所以s1==s5(false)。s6引用的是堆内存String对象,s1与s5指向不同的内存,地址不同,所以s1==s6(false)。
通过a、b两种情况的讨论我们可以得出==的核心是“比较值是否相等”,这个值可以是基本数据类型的值,也可以是引用对象在内存中的地址(地址本质上也是一个值)。
2、equals()方法
类Object是类层次结构的跟类。每个类都能使用Object作为超类。所有对象(包括数组)都实现这个类的方法。equals()就是定义在Object类中的public方法,所以equals()方法被java中的所有类所继承。
我们先来看一下Object类中是如何定义equals()方法的:
*
指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:
自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值 x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
参数:
obj - 要与之比较的引用对象。
返回:重点内容
如果此对象与 obj 参数相同,则返回 true;否则返回 false。
*
总结起来就是:Object类中实现的equals方法,比较的是两个引用类型变量是否指向同一个对象,换句话说就是这两个引用类型变量的值是否相等。在功能上与“==”是一样的。
而我们在实际编码中需要有特殊的equals逻辑(例如Student和Teacher类都有id和name这两个字段,只要它们的值相等,我们就认为这两个类的对象是相等的,返回true**)。**这时用Object类的equals方法是不能实现的。所以我们必须在类中用我们自己定义的规则重写从Object类继承的equals方法。
由于从Object类中继承的equals方法实战是不好用,所有jdk中的很多类都重写了从Object类中继承的equals方法,如String类,下面给出String类中equals方法的定义:
public boolean equals(Object anObject)将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。
覆盖:
类 Object 中的 equals
参数:
anObject - 与此 String 进行比较的对象。
返回:
如果给定对象表示的 String 与此 String 相等,则返回 true;否则返回 false。
注意这句话“与此对象表示相同字符序列的 String 对象时,结果才为 true。 ”可见String类的equals方法比较的是String对象中的字符序列。举个例子:
String s1 = new String("abc");
String s2 = new String("abc");
s1.equals(s2);//结果是true,因为String类的equals方法比较的是字符串序列。
所以在使用“==”时要记得它比较的值,使用equals方法时要注意查看相应类的api文档,确定equals方法到底是如何定义的后者自己重写equals方法。