Object类
Object作为所有类的父类,我们还是有必要知道Object类下的一些方法的实现原理。
toString()方法:
public String toString()
我们可以根据官方手册可以知道,tostring()方法是,返回对象的字符串表示形式。 一般来说, toString
方法返回一个“textually代表”这个对象的字符串。 结果应该是一个简明扼要的表达,容易让人阅读。 建议所有子类覆盖此方法。
package com.lyc.lesson;
class Person{
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class Lesson01 {
public static void main(String[] args) {
Person person = new Person("张三");
//我们在不重写toString方法时,得到的Person对象为:com.lyc.lesson.Person@1b6d3586,
System.out.println(person);
}
}
//重写toString方法后
Person{name='张三'}
equals()方法:
//Object类中equals方法的源码
public boolean equals(Object obj) {
return (this == obj);
}
从上述代码我们知道,Object 类下面的方法比较是两个对象的地址
,不看内容
。
那为什么String类下面的equals方法是比较的内容?这是因为String类继承了Object类,并重写了equals方法。比如我们有一个需求:需要比较两个字符串内容是否相等。这时我们就发现Object类下的equals方法已经不能满足我们的需求,因此我们要重写这个equals方法。
package com.lyc.lesson;
import java.util.Objects;
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//stu1.equals(stu2)
//stu2赋值给了 o 向上转型 Object o =new Student();
@Override
public boolean equals(Object o) {
if (this == o) { //比较是地址
return true;
}
//如果地址不一样的话,再去比较内容,如果内容一样也返回true
if (o instanceof Student) {
//o instanceof Student : o 属于 Student的子类或本类,才去比较值 name age
Student stu = (Student)o;//向下转型
//stu1.equals(stu2) stu ---> stu2 , this ---> stu1
//stu.name.equals(this.name):字符串的equals方法比较的是内容
return stu.age == this.age && stu.name.equals(this.name);
}
return false;
}
}
public class Lesson04 {
public static void main(String[] args) {
Student stu1 = new Student("张三", 89);
Student stu2 = new Student("张三", 89);
/**
* 当我们不重写toString方法时,因为stu1是Object类的子类
* 所以用的是object类面下的equals方法
* Object类下面的equals方法比较是 地址 this==obj
*/
//System.out.println(stu1.equals(stu2));//false
/**
* 现在我的需求是当两个对象的内容一致的时候返回的是true,内容不一样的时候,返回是false
* 就意味着Object类的equals方法已经满足不了Student类的需求了
* 这时我们就重写equals方法
*/
System.out.println(stu1.equals(stu2));//true
}
}
hashCode()方法:
哈希码值:在Object类下面,将内存地址(十六进制的值)转为十进制的值,此时这个十进制的值就叫hash码。
在hashCode的注意事项中我们值得注意的是:如果根据
equals(Object)
方法两个对象相等,则在两个对象中的每个对象上调用hashCode
方法必须产生相同的整数结果。
package com.lyc.lesson;
class Cat{}
public class Lesson05 {
public static void main(String[] args) {
Cat cat = new Cat();
Cat cat1 = new Cat();
//对象不同hash值不同
System.out.println(cat.hashCode()); //460141958
System.out.println(cat1.hashCode());//1163157884
String str = new String("a");
String str1 = new String("b");
String str2 = new String("a");
System.out.println(str.hashCode()); //97
System.out.println(str1.hashCode()); //98
System.out.println(str2.hashCode()); //97
}
}
但是通过上述案例,我们发现在String类下的hashCode方法中str和str2的内存地址不一样,但hash值一样,为什么?这也是因为String类重写了hashCode方法。
在查看官方手册时,我们还要注意一个点,就是“请注意,无论何时重写equals方法,通常需要重写
hashCode
方法,以便维护hashCode
方法的通用合同,该方法规定相等的对象必须具有相等的哈希码”。
我们对上述注意事项做出分析:情况1、相等对象内容,但是不重写hashCode方法。
package com.lyc.lesson;
import java.util.Objects;
class Dog {
int id;
String name;
public Dog(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals (Object o) {
if (this == o) {
return true;
}
if (o instanceof Dog) {
Dog dog = (Dog)o;
return this.id == dog.id && dog.name.equals(this.name);
}
return false;
}
// @Override
// public int hashCode() {
// return name.hashCode() + id;
// }
}
public class Lesson06 {
public static void main(String[] args) {
//现在关注的是内容,我们重写并调用equals方法
Dog dog1 = new Dog( 2, "b");
Dog dog2 = new Dog( 2, "b");
System.out.println(dog1.equals(dog2));//true
//当我们不重写hashCode时,这个两个对象的hash值不一样,因为内存地址不一样的.
System.out.println(dog1.hashCode()); //460141958
System.out.println(dog2.hashCode()); //1163157884
}
}
情况2、对象内容不一样,但是重写hashCode方法,使hahsCode值一样。
package com.lyc.lesson;
import java.util.Objects;
class Dog {
int id;
String name;
public Dog(int id, String name) {
this.id = id;
this.name = name;
}
public boolean equals (Object o) {
if (this == o) {
return true;
}
if (o instanceof Dog) {
Dog dog = (Dog)o;
return this.id == dog.id && dog.name.equals(this.name);
}
return false;
}
@Override
public int hashCode() {
return name.hashCode() + id;
}
}
public class Lesson05 {
public static void main(String[] args) {
Dog dog1 = new Dog( 3, "a");
Dog dog2 = new Dog( 2, "b");
System.out.println(dog1.equals(dog2));//false
//我们通过重写hashCode方法,使hashCode值一样。
System.out.println(dog1.hashCode()); //100
System.out.println(dog2.hashCode()); //100
}
}
因此,我们可以得出一个结论:
如果两个对象的hash值一样,对象是不一定一样的。但是如果两个对象相等那么hash值一定相等。
并且,equals方法和hashCode方法可以说是共生关系,要重写是全部都要重写,缺一不可。即“无论何时重写equals方法,通常需要重写
hashCode
方法,以便维护hashCode
方法的通用合同,该方法规定相等的对象必须具有相等的哈希码”。”