Java Object类默认方法

默认方法

一、toString()方法

每个类都继承自 Object 类,而 Object 类中有一个默认的 toString() 方法。默认情况下,toString() 方法返回的是 类的全名(包括包名)该类实例的哈希值(以十六进制表示)。

默认的 toString() 方法:

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

解释 :

  1. getClass().getName():返回当前对象所属的类的全名(包括包名)。
  2. hashCode():返回对象的哈希值,它是基于对象的内存地址生成的,默认情况下,hashCode() 的值与该对象的内存地址相关,但它并不直接等于内存地址。hashCode() 是一个整数值,用十六进制表示。
  3. Integer.toHexString(hashCode()):将哈希值转换为十六进制字符串。

示例:

public class Demo {
    public static void main(String[] args) {
        Object obj = new Object();  // 创建一个 Object 类的实例
        System.out.println(obj.toString());  // 调用默认的 toString 方法
    }
}

输出:

java.lang.Object@1b6d3586

自定义 toString() 方法:

通常,开发者会重写 toString() 方法,以便返回更有意义的对象描述(而不仅仅是类名和哈希值)。比如,返回对象的字段值:

示例:重写 toString() 方法
class Dog {
    String name;
    int age;

    Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy", 5);
        System.out.println(dog);  // 调用重写后的 toString 方法
    }
}
输出:
Dog{name='Buddy', age=5}

二、equals()方法

equals() 方法是 Object 类的一个方法,它用于比较两个对象是否相等。所有的类都继承了 Object 类,因此每个类都有一个 equals() 方法。如果没有在子类中重写 equals() 方法,那么将使用 Object 类中的默认实现。

1. equals() 方法的默认实现:

Object 类中的默认 equals() 方法是通过比较两个对象的 引用地址 来判断它们是否相等的。默认的实现如下:

public boolean equals(Object obj) {
    return (this == obj);  // 判断引用是否相同
}
解释:
  • this == obj:比较的是对象引用的地址,即 this(当前对象)和 obj(传入的对象)是否指向同一个内存地址(即它们是否是同一个对象)。

2. 默认 equals() 方法的行为:

  • 引用相同的对象:如果两个引用变量指向的是同一个对象(即它们的内存地址相同),则 equals() 返回 true
  • 引用不同的对象:即使两个对象的内容完全相同,只要它们是不同的对象实例(即内存地址不同),默认 equals() 方法会返回 false

示例代码(使用 Object 类的默认 equals() 方法):

class Dog {
    String name;

    Dog(String name) {
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog1 = new Dog("Buddy");
        Dog dog2 = new Dog("Buddy");
        
        // 使用默认的 equals 方法比较 dog1 和 dog2
        System.out.println(dog1.equals(dog2));  // 输出 false
    }
}

解释:虽然 dog1dog2 都是 Dog 类的对象,并且它们的 name 属性都为 "Buddy",但是因为它们是两个不同的对象(即内存地址不同),所以默认的 equals() 方法返回 false

3. 为什么 equals() 方法默认比较引用地址?

默认的 equals() 方法的设计是基于对象的引用地址,因为在没有重写 equals() 方法的情况下,Java 默认假定对象的相等性是由它们的内存地址(引用)来决定的。这是因为 Object 类的 equals() 方法只知道对象的引用,没有关于对象内容的其他信息。

4. 如何重写 equals() 方法?

如果你希望比较两个对象的内容是否相等(而不仅仅是引用是否相同),你应该在类中 重写 equals() 方法。重写 equals() 方法时,通常会比较对象的 字段值 是否相等。

重写 equals() 方法的规则:
  • 自反性(Reflexive):对于任何非 null 的引用值 xx.equals(x) 应该返回 true
  • 对称性(Symmetric):对于任何非 null 的引用值 xy,如果 x.equals(y) 返回 true,则 y.equals(x) 也应该返回 true
  • 传递性(Transitive):对于任何非 null 的引用值 xyz,如果 x.equals(y) 返回 true,且 y.equals(z) 返回 true,那么 x.equals(z) 应该返回 true
  • 一致性(Consistent):对于任何非 null 的引用值 xy,如果在 x.equals(y) 多次调用中没有发生改变,那么应该一直返回相同的结果。
  • null 的处理:对于任何非 null 的引用值 xx.equals(null) 应该返回 false
示例:重写 equals() 方法
class Dog {
    String name;

    Dog(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        // 如果是同一个对象,直接返回 true
        if (this == obj) {
            return true;
        }
        
        // 如果传入的对象为 null 或类型不一致,返回 false
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        // 强制转换为 Dog 类型
        Dog dog = (Dog) obj;

        // 比较 name 字段
        return name != null && name.equals(dog.name);
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog1 = new Dog("Buddy");
        Dog dog2 = new Dog("Buddy");
        
        // 使用重写后的 equals 方法比较 dog1 和 dog2
        System.out.println(dog1.equals(dog2));  // 输出 true
    }
}

在上面的代码中,我们重写了 equals() 方法,确保两个 Dog 对象的 name 字段相同就被认为是相等的。由于 dog1dog2name 都是 "Buddy",所以 dog1.equals(dog2) 返回 true

5. equals() 方法的常见应用:

  • 对象内容比较equals() 方法常用于比较两个对象是否具有相同的内容。例如,在比较两个字符串、两个自定义对象时,重写 equals() 方法是必不可少的。
  • 集合操作:在使用 HashSetHashMap 等集合类时,通常会用到 equals() 方法来判断对象是否已经存在于集合中。

6. 总结:

  • 默认的 equals() 方法:比较的是对象的引用地址,即判断两个对象是否是同一个实例(引用是否相同)。
  • 重写 equals() 方法:用于比较两个对象的内容,通常会根据对象的字段值来判断它们是否相等。
  • 重写 equals() 方法时,通常还需要重写 hashCode() 方法,这是因为 equals()hashCode() 在集合操作中通常是一起使用的。如果两个对象相等(equals() 返回 true),它们的哈希值也应该相同。

三、hashCode()方法

hashCode()Object 类的一个方法。每个 Java 对象都有一个与之关联的哈希码(hash code),它是一个整数值,用于表示对象的内存地址的某种方式。hashCode() 方法的默认实现返回的是对象的 内存地址 的某种整数表示。

1. hashCode() 方法的定义和默认实现

hashCode() 方法是 Object 类的一部分,它返回一个 32 位的整数,该整数通常是对象的内存地址的哈希值。Object 类的默认实现如下:

public int hashCode() {
    return System.identityHashCode(this);
}

System.identityHashCode(this) 返回当前对象的内存地址的哈希码,它是通过 JNI(Java Native Interface)来实现的。这就是为什么 hashCode() 默认返回的是基于内存地址的哈希值。

2. hashCode() 方法的作用

hashCode() 方法的主要作用是在基于哈希表的数据结构中(如 HashMapHashSetHashtable 等)查找、存储和删除对象时提高效率。哈希码帮助哈希表将对象映射到一个特定的桶中,从而优化查找操作。

3. hashCode()equals() 的关系

在 Java 中,hashCode() 方法和 equals() 方法有着紧密的关系,特别是在使用集合类(如 HashMapHashSet)时。根据 Java 的规定:

  • 如果两个对象通过 equals() 比较相等,那么它们的 hashCode() 必须相等。
  • 如果两个对象的 hashCode() 相等,equals() 不一定返回 true,但是如果 equals() 返回 true,则它们的 hashCode() 必须相等。

4. 为什么 hashCode() 需要与 equals() 一起重写?

如果你在自定义类中重写了 equals() 方法,那么为了避免潜在的问题(特别是在使用哈希集合类时),你通常也需要重写 hashCode() 方法。否则,集合类(如 HashSet)可能无法正常工作,因为它们使用 hashCode() 来高效查找对象。

5. hashCode() 的默认行为示例

让我们先看一下 hashCode() 方法的默认实现如何工作:

示例:使用默认 hashCode() 方法
class Dog {
    String name;

    Dog(String name) {
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog1 = new Dog("Buddy");
        Dog dog2 = new Dog("Buddy");

        System.out.println(dog1.hashCode());  // 输出 dog1 的哈希值
        System.out.println(dog2.hashCode());  // 输出 dog2 的哈希值
    }
}
输出(每次运行可能不同):
2073669225
1398586099

解释:dog1dog2 是两个不同的 Dog 对象,它们的内存地址不同,因此它们的 hashCode() 也不同。默认情况下,hashCode() 返回的是对象的内存地址的某种整数表示,因此每次运行时值可能会有所不同。

6. 重写 hashCode() 方法的建议

如果你重写了 equals() 方法来比较两个对象的内容,那么你通常也应该重写 hashCode() 方法来确保它们的哈希值一致。下面是重写 hashCode() 方法的常见做法。

重写 hashCode() 方法的规则:
  1. 相等的对象必须具有相等的哈希值:如果 x.equals(y) 返回 true,那么 x.hashCode() 必须等于 y.hashCode()
  2. 不相等的对象不要求具有不同的哈希值:不同的对象可能有相同的哈希值,这被称为哈希冲突。
  3. 一致性:在一个程序的运行期间,如果对象的属性没有改变,hashCode() 的值应始终保持一致。
示例:重写 hashCode() 方法
class Dog {
    String name;
    int age;

    Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Dog dog = (Dog) obj;
        return age == dog.age && name.equals(dog.name);
    }

    @Override
    public int hashCode() {
        int result = 17;  // 任意非零常数
        result = 31 * result + (name != null ? name.hashCode() : 0);  // name 字段的哈希值
        result = 31 * result + age;  // age 字段的哈希值
        return result;
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog1 = new Dog("Buddy", 5);
        Dog dog2 = new Dog("Buddy", 5);

        System.out.println(dog1.hashCode());  // dog1 的哈希值
        System.out.println(dog2.hashCode());  // dog2 的哈希值

        System.out.println(dog1.equals(dog2));  // 输出 true,因为 name 和 age 相等
    }
}
输出:
1998091196
1998091196
true

解释:在重写 hashCode() 方法后,dog1dog2 都有相同的哈希值(因为它们的 nameage 字段相同),而且 equals() 方法也返回 true,表示这两个对象是相等的。

7. hashCode() 和集合类

hashCode() 在使用集合类时非常重要,尤其是 HashMapHashSetHashtable 等,它们使用哈希码来优化查找、存储和删除操作。例如:

示例:使用 HashSethashCode()
import java.util.HashSet;

class Dog {
    String name;
    int age;

    Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Dog dog = (Dog) obj;
        return age == dog.age && name.equals(dog.name);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + age;
        return result;
    }
}

public class Test {
    public static void main(String[] args) {
        HashSet<Dog> set = new HashSet<>();
        Dog dog1 = new Dog("Buddy", 5);
        Dog dog2 = new Dog("Buddy", 5);

        set.add(dog1);
        set.add(dog2);

        System.out.println(set.size());  // 输出 1,因为 dog1 和 dog2 被认为是相等的
    }
}

在这个例子中,dog1dog2 被认为是相等的,因为它们的 nameage 字段相等,且它们的 hashCode() 相同。因此,它们被认为是相同的对象,不会被添加到 HashSet 中两次。

8. 总结

  • hashCode() 方法返回对象的哈希码,默认实现基于对象的内存地址。
  • 在自定义类中,如果重写了 equals() 方法,通常需要重写 hashCode() 方法。
  • 重写 hashCode() 方法时,必须保证 相等的对象有相同的哈希值
  • hashCode() 方法广泛应用于集合类,如 HashMapHashSet,以便快速查找和存储对象。

在不使用hash集合的时候,可以仅需要重写equals(),否则一定重写hashCode()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值