1,==的理解
①,既可以判断基本类型,又可以判断引用类型
②,如果判断基本类型,判断的是值是否相等,例如:int i=10,double d=10.0
③,如果判断的是引用类型,判断的是地址是否相等,即判定是不是同一个对象。
例如源代码:
package com.whpu.equals_; public class equals_1 { public static void main(String[] args){ int i=10; double d=10.0; System.out.println(i==d); B b=new B(); B a=b; System.out.println(a==b); } } class A{} class B{}
第一个比较的是基本类型,值得注意的是,10和10.0它们的值是相同的,虽然数据类型不一样。
第二个比较的是引用类型,创建两个B类对象,分别用b和a引用对象名去指向这个B对象,所以这个时候比较的是地址,a和b指向的地址是同一个地方,所以比较结果是相同的。
二,equals的理解
重点来了!!!
用equals去比较两个数是不是相等的分两类,第一类,这两个变量类型不对equals中的方法造成重写,比如我们自己命名的Student类名,就是不构成重写的,这个时候用这个stu变量去引用equals方法时,调用的是Object中的equals方法,只比较地址是不是一样的,而不比较内容是不是一样的。例如下图源代码:
因为每new一个student,就会在堆区中创建一个新对象,它new了两个Student,所以就会在堆内创建两个Student对象,分别用stu1和stu2去指向。很显然,它们的地址是不一样的,而且在Student方法中是没有equals方法的,所以也不存在造成equals方法的重写,直接调用的就是Object中的equals方法。比较地址是不是一样的,如果不一样,则返回false,一样则返回true。题目中是返回false的。
下面提供
Object中的equals方法。
public boolean equals(Object obj){
return(this == obj); //用==判断地址一不一致,不一致则为false,返回,否则返回true。
}
就短短的三行。
第二种情况,如果我们要比较的两个变量它们的类型例如String中有equals方法的重写,那么调用这个equals方法时,先执行运行类型的变量类型中的equals方法,而这个重写的变量类型的方法中,它和Object中的equals方法是不大一样的,它在原来Object中的equals的基础上新加了一个用来判断内容是否一样的if语句,也就是说,如果这两个比较的变量即使它们的地址是不一样的,只要它们的内容是一样的,也被认为是true的。
下面提供一个String类中equals的方法。
String类中equals源代码
public boolean equals(Object anObject) {
// 第一个if,判断两者是否是同一个内存地址
if (this == anObject) {
return true;
}
// 第二个if,判断两者的值是否相同(将每个字符逐一比较)
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对象,对象内都有hello内容,显然,这两个对象用u1和u2指向的地址是不一样的,一个指向的是u1的实例对象,一个指向的是u2的实例对象,但是由于String类型它调用equals方法时,造成了equals方法的重写,所以系统就首先会考虑调用运行类型的String类中的equals方法,而不会首先考虑编译类型中的Object中的方法。来到了String中的equals方法中,也就是上面三张图的第一张,有String类中equals的原码,第一步还是比较地址是不是一样的,很显然,u1和u2分别指向两个不同的String实例对象,所以地址是不一样的,因此第一个if语句不会被调用。接着往下,到第二个if语句,因为Object是所有类的超类,所以可以用到对象的多态,用Object anObject去接收一个String u2类,接收了之后,anObject就是父类的引用指向子类的对象String类了,构成一个向上转型,接着第二个if语句的意思就是这个父类的引用anObject它的运行类型是不是String类型,很显然是,因为前面我们用Object anObject去接收String u2,所以编译类型是Object,运行类型是String,所以第二个if语句通过。接着就来一波向下转型的操作,因为后面是想调用String类中的特有属性的值,而anObject作为父类的引用,只能调用到子类中父类有的方法,而不能调用父类没有的方法或属性,所以必须将原来的anObject父类的引用向下转型为子类,也就是String anotherString=(String) anObject,这样,就可以使用anotherString来调用这个特有的属性值了,后面的步骤就是比较两个值的内容是否相同,通过拆分数组比较的方法,最终两个相同的hello显然是相同的,所以返回true。
三,总结
==比较方法很简单,主要是equals方法,要考虑重写,如果子类类型没有重写,则直接调用Object中的equals方法,单纯的比较两个变量地址是否一样,如果子类类型有重写,因为我们知道,看equals的原码都是使用Object anObject去接收对象的,所以Object总是为编译类型,而子类类型总是运行类型,所以如果有重写equals方法,首先考虑采用的是运行类型的equals方法,也就是String中的equals方法,而这个子类的equals方法在原来Object中的equals方法的基础上新加了一个if语句用来判断对象中的内容是否相等,所以即使两个变量的地址不一样,只要它们的内容是一样的,还是会返回true的,这就是equals方法的主要区别。不懂就看equals在Object和子类重写方法中的原码,自己多看看,分析分析!!!