新手学Java绕不开的“老祖宗”:Object类,一篇讲透equals、hashCode、==的核心区别✨

一、开篇唠唠:为啥Object是Java界的“老祖宗”?

你写的每一个Java类,哪怕只敲了class Person {},背后都藏着一个默认的继承关系——extends Object。

Object类就像Java世界的“创世神”,是所有类的根父类(没有之一),不管是String、Integer这些系统类,还是你自定义的实体类,全都继承了Object的“血脉”。

也正因为如此,你随手new的任何对象,都能直接调用equals()、hashCode()、toString()这些方法——这些都是“老祖宗”给所有子孙的标配技能!

二、Object的“三板斧”:最常用的3个API

Object类的方法不少,但对新手来说,核心就这3个,咱们挨个掰扯清楚👇

2.1 toString():别再让对象打印成“乱码”了

默认行为:Object的toString()源码长这样,默认打印「类全名@十六进制哈希值」:

public String toString() {
return getClass().getName() + “@” + Integer.toHexString(hashCode());
}

比如你new一个Person对象直接打印:

class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}

public class ObjectDemo {
public static void main(String[] args) {
Person p = new Person(“张三”, 20);
System.out.println§; // 输出:com.test.Person@15db9742(一串看不懂的字符)
}
}

实用技巧:重写toString(),让打印结果“人话化”:

class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 重写toString()
@Override
public String toString() {
    return "Person{name='" + name + "', age=" + age + "}";
}

}

// 此时打印p会输出:Person{name=‘张三’, age=20}

2.2 equals():别再用==比较对象了!

默认行为:Object的equals()本质就是==,比较的是两个对象的内存地址:

public boolean equals(Object obj) {
return (this == obj);
}

举个反例,你觉得下面代码会输出true吗?

Person p1 = new Person(“张三”, 20);
Person p2 = new Person(“张三”, 20);
System.out.println(p1.equals(p2)); // 默认输出false!

哪怕p1和p2的姓名、年龄完全一样,因为是两个不同的对象(内存地址不同),默认equals也会返回false。

实用技巧:重写equals(),按“内容”比较对象:

@Override
public boolean equals(Object o) {
// 1. 地址相同,直接返回true
if (this == o) return true;
// 2. 对方是null/类型不同,返回false
if (o == null || getClass() != o.getClass()) return false;
// 3. 强转后比较属性
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}

此时再调用p1.equals(p2),就会返回true了(内容相等)。

2.3 hashCode():对象的“唯一标识码”?

默认行为:hashCode()是本地方法(native),默认返回对象内存地址的哈希值,可理解为对象的“内存身份证”。

核心作用:哈希相关集合(HashMap、HashSet等)的“核心钥匙”——这些集合会先通过hashCode定位对象的“大致位置”,再用equals精准匹配。

⚠️ 重点:重写equals时,必须同步重写hashCode()!否则会导致HashMap等集合存储异常。

比如重写Person的hashCode:

@Override
public int hashCode() {
return Objects.hash(name, age); // 按属性生成哈希值
}

三、灵魂拷问:== 和 equals 到底差在哪?

新手最容易搞混的两个“比较符”,用表格一次性说透👇

比较方式

基本数据类型(int/char等)

引用数据类型(Object/自定义类)

==

比较值是否相等

比较内存地址是否相等

equals

无此用法(基本类型不是对象)

默认比较内存地址,重写后可比较内容

💡 举个栗子:

// 基本类型:== 比的值
int a = 10;
int b = 10;
System.out.println(a == b); // true

// 引用类型:== 比地址,equals重写后比内容
String s1 = new String(“Java”);
String s2 = new String(“Java”);
System.out.println(s1 == s2); // false(地址不同)
System.out.println(s1.equals(s2)); // true(String已重写equals)

四、绑定CP:hashCode和equals的“爱恨情仇”

这俩的关系是Java面试高频题,核心就两句话:

  1. equals相等 → hashCode一定相等:如果两个对象equals返回true(内容相同),它们的hashCode必须相同(否则HashMap会把同一个对象当成两个);

  2. hashCode相等 ≠ equals一定相等:这就是“哈希碰撞”——不同内容的对象,可能生成相同的哈希值(比如字符串"Aa"和"BB"的hashCode都是2112)。

🚨 反例:如果只重写equals不重写hashCode:

Person p1 = new Person(“张三”, 20);
Person p2 = new Person(“张三”, 20);
System.out.println(p1.equals(p2)); // true(重写后)
System.out.println(p1.hashCode() == p2.hashCode()); // false(默认按地址生成)

// 存入HashSet会被当成两个对象(本应是一个)
HashSet set = new HashSet<>();
set.add(p1);
set.add(p2);
System.out.println(set.size()); // 输出2(错误!)

五、总结:核心知识点回顾

  1. Object是所有Java类的父类,所有对象都能调用它的toString/equals/hashCode方法;

  2. ==对基本类型比“值”,对引用类型比“地址”;equals默认比地址,重写后可比“内容”;

  3. hashCode和equals必须成对重写,遵循“equals相等则hashCode必相等”的规则。

吃透Object类的这几个核心点,你就能避开80%的Java对象比较坑啦!如果觉得有用,记得点赞收藏~

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐