先说一下Object类吧:
这是一个号称为祖宗类的东西,是所有类的父类,也是唯一一个没有父类的类。
接口不继承object类
并且Object类存在于java的lang包中,我们都知道存在于lang包中的类我们是可以直接使用的,后面总结的也都是这方面的
今天说一下Object类中的equals方法吧
对于这个方法的总结最先有些懵,借鉴了https://www.cnblogs.com/dolphin0520/category/361055.html这个大神写的一些东西,受益很大,在重写了一些equals方法后也算是彻底掌握了
一.其源码
public boolean equals(Object obj) { return (this == obj); }
二.该方法和“==”的区别
这是来自于《java编程思想》的一段原话:
“关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系”
简单来说“==”是用来判断两个变量之间是否相等。
equals方法是用来比较地址是否相同的(我们根据上面的源码来解释一下吧)
this==obj obj是我们传过来的对象地址,this存放的是本类对象的地址
public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int n=3; int m=3; System.out.println(n==m); String str = new String("hello"); String str1 = new String("hello"); String str2 = new String("hello"); System.out.println(str1==str2); str1 = str; str2 = str; System.out.println(str1==str2); } } 结果: true false true
对于第一个结果相信我们都知道是为什么:因为他直接比较的数值的值是否相等3==3所以返回值一定是true。
对于第二个结果就会有些不理解了:上面不是说“==”比较的是数值是否相同吗? 在这里我们应该了解到引用类型的变量存的并不是数值,他们存的是每一个对象的地址,我们每实例化一个对象就会在堆中重新创建一个对象,其地址不一样. 所以这里因为地址不一样所以返回值为false。
那么对于第三个结果就很好解释了:我们使str1,str2地址相等,所以返回值一定是true。
所以从这里可以看出来“==”比较的是具体数值,但就看你变量存的是啥数值了,可能是地址,或者一个值之类的。
三.通过一个代码来说明一些问题
public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String str1 = new String("hello"); String str2 = new String("hello"); System.out.println(str1.equals(str2)); } }
结果:true
四.对于上面问题的解释
我们上面说了equals方法比较的是地址,实例化之后地址一定不一样了.但为什么上面程序结果是true
我们应该知道Object是所有类的父类,String类也不例外.可是身为子类,总得有点特权吧(要不然这爹白叫了),没错重写方法,因为在String类中重写了equals方法,所以比较的就不再是地址了,而是传过去的参数.
至于他是怎样比较的,我在下面会将我的比较自己写的简陋但易懂的重写方法写出来
现在这里是java中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; }
五.我重写的equals方法
public class NewLife { private int age; private String name; public NewLife(int age,String name) { this.age=age; this.name=name; } public boolean equals(Object obj){ if(this==obj) { return true; } else if(obj instanceof NewLife) { // Object obj=new NewLife(); 此处涉及到了多态 NewLife nl=(NewLife)obj; if(this.age==nl.age) { return true; } } return false; } } public class Test { public static void main(String[] args) { NewLife n1=new NewLife(12,"lihaiya"); NewLife n2=new NewLife(13,"dazhizhang"); boolean a=n1.equals(n2); System.out.println(a); } }
我们能够注意到不论是我的重写,还是系统中的那个重写,都存在有强转这一操作原因如下:
我还是通过代码来说明对象等级的变化吧
NewLife n2=new NewLife(13,"dazhizhang");
1.这里的n2先是子类的一个对象
public boolean equals(Object obj)
2.obj就是我们传过去的n2,为什么要升高他的等级,我们倒也不想,但是我们重写的是父类中的方法,我们能改变的只是其内容,但是其所传参数的类型我们是绝对没有资格改的
所以这里n2从一个小小的子类对象变成了父类的对象 而且这里涉及到了多态下面就是隐藏的代码了
Object obj=new NewLife();
3.下面是强转的操作了
NewLife nl=(NewLife)obj;
为什么要强转,因为在我重写的方法中,我要比较的是子类中age是否相同,但是根据多态的性质,变量的查找是严格可着父类来的,如果子类中有父类中没有的话,系统是会报错的,所以这里我们必须把Object类型的obj转成子类NewLife类型才行。
另外还有一个判定是否需要强转的技巧,当我们不确定一个对象是否需要强转时,试着用变量名.的方式调用一下父类中没有,子类中存在的变量试试,报错的话,就要考虑一下等级问题了
六.总结
对于这个方法的理解最重要的还是自己能够重写出来一个equals方法。
因为在重写的过程中很多我们没有注意到或者不想去想的问题就会暴露出来。