Object 是一个具体的类,但它主要是为扩展而设计的。它的所有非 final 方法(equals、hashCode、toString、clone 和 finalize)都有显式的通用约定,因为它们的设计目的是被覆盖。任何类都有责任覆盖这些方法并将之作为一般约定;如果不这样做,将阻止依赖于约定的其他类(如 HashMap 和 HashSet)与之一起正常工作。

一个类要么默认继承了 Object 类,要么间接继承了 Object 类,Object 类是 Java 中的祖宗类。Object 类的方法是一切子类都可以直接使用的。
Object 类的常用方法:

toString

public String toString():默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址,例如 entity.Student@34ce8af7

  1. public class ObjectTest {
  2. public static void main(String[] args) {
  3. Student student = new Student("Halo", '男', 18);
  4. System.out.println(student.toString());
  5. // 直接输出对象变量,默认可以省略 toString()
  6. System.out.println(student);
  7. }
  8. }
  • 开发中直接输出对象,默认输出对象的地址其实是毫无意义的。
  • 开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息。

父类 toString() 方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息。

@Override
public String toString() {
    return "Student{" +
        "name='" + name + '\'' +
        ", sex=" + sex +
        ", age=" + age +
        '}';
}

IDEA 中使用 Alt + Ins 或输入 tos 调用重写方法

equals

public Boolean equals(Object o):默认是比较当前对象与另一个对象的地址是否相同,相同返回 true,不同返回 false。
若直接比较两个对象的地址是否相同完全可以用“==”替代 equals。
父类 equals 方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则。

@Override
public boolean equals(Object o) {
    // 判断是否是同一个对象
    if (this == o) {
        return true;
    }
    // 如果 o 是 null、o 不是 this 对应类型返回 false
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    Student student = (Student) o;
    return sex == student.sex && age == student.age && Objects.equals(name, student.name);
}
@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (!(o instanceof Student)) {
        return false;
    }
    Student student = (Student) o;
    return sex == student.sex && age == student.age && Objects.equals(name, student.name);
}

注:在重写的 equals 进行字符串比较时,没有对象自己的 equals 方法,而是选择了 Objects 的 equals 方法来比较两个对象。Object.equals() 方法比较的结果是一样的,但是更安全。

public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

以上两种重写 equals 的方式区别在与 x.getClass() == y.getClass()x instanceof y

getClass() 返回一个对象所属的类,返回的是一个类名,不会判断子类与父类的继承关系:

public class Human {
    private String name;
    private char sex;
    private int age;

    public Human(String name, char sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public Human() {

    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Student extends Human {
    private int grade;
    private int id;

    public Student(String name, char sex, int age) {
        super(name, sex, age);
    }

    public Student(String name, char sex, int age, int grade, int id) {
        super(name, sex, age);
        this.grade = grade;
        this.id = id;
    }

    public Student() {
    }

    public Student(int grade, int id) {
        this.grade = grade;
        this.id = id;
    }

    public int getGrade() {
        return grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
public static void main(String[] args) {
    Student student = new Student("Halo", '男', 18);
    Human human = new Human("Halo", '男', 18);

    System.out.println(student.getClass());
    System.out.println(human.getClass());
}

// OutPut:
// class entity.Student
// class entity.Human

instanceof 比较一个对象是否是该类的实例:

public static void main(String[] args) {
    Student student = new Student("Halo", '男', 18);
    Human human = new Human("Halo", '男', 18);

    System.out.println(student.getClass() == human.getClass()); // false

    System.out.println(student instanceof Object);  // true
    System.out.println(student instanceof Student); // true
    System.out.println(student instanceof Human);   // true
    System.out.println(human instanceof Student);   // false
}

instanceof 会判断继承关系,子对象 instanceof 父类 会返回 true,父对象 instanceof 子类会返回 false。 可以理解为判断两个问题:你是这个类吗? 你是这个类的派生类吗?

故使用 instanceof 判断,则以下结果返回 true,而 getClass 方法判断则会返回 false

public static void main(String[] args) {
    Student student = new Student("Halo", '男', 18);
    Human human = new Human("Halo", '男', 18);
    System.out.println(human.equals(student));
}

equals 的最佳实践 TODO

equals 方法需要具有下面特性:

  • 自反性:对于任何非 null 的参考值 x,x.equals(x) 必须返回 true。
  • 对称性:对于任何非 null 参考值 x 和 y,x.equals(y) 必须在且仅当 y.equals(x) 返回 true 时返回 true。
  • 传递性:对于任何非 null 的引用值 x, y, z,如果 x.equals(y) 返回 true,y.equals(z) 返回 true,那么 x.equals(z) 必须返回 true。
  • 一致性:对于任何非 null 的引用值 x 和 y,只要 equals 的比较操作在对象中所用的信息没有被修改,多次调用 x.equals(y) 就会一致地返回 true,或者一致地返回 false。
  • 对于任意非空引用 x,x.equals(null) 应该返回 false。

    参考 链接、《Effective Java》第3版