Java Object类用法详解(附带实例)
在 Java 类型关系中,所有类都直接或间接依赖 Object 类,Object 类位于继承树的顶层。
在 Java 程序中,如果一个类没有显示声明继承某个类,就默认直接继承 Object 类。Object 类提供无参数构造方法,不提供有参数构造方法。虽然程序一般并不会直接调用 new Object(),但在子类对象实例化时都会默认调用父类中的无参数构造方法。
所有对象都能调用 Object 类中定义的公有方法,如 hashCode()、equals()、toString() 等。尽管 Object 类是一个具体类,但设计它的主要目的是拓展。下面对一些常用方法进行介绍。
注意,同一个对象多次调用 hashCode() 方法必须得到相等的散列码,但相同的散列码不能说明两个对象一定是同一个对象。
【实例 1】使用 hashCode() 方法判断两个对象是否是同一个对象,代码如下:
【实例 2】使用 equals() 方法判断两个对象内容是否相等,代码如下:
若散列值不相等,则说明两个对象不是同一个对象;
若散列值相等,则需要进一步调用 equals() 方法判断。
逻辑说明如下:
若两个对象的引用地址相等,则返回 true 并结束后续判断 (x.equals(x));若引用地址不一致,则将进一步判断。
若类型也相同,则进一步做以下判断:
覆盖 equals() 方法时应该同时覆盖 hashCode() 方法,因为相等的对象必须具有相同的散列码。
注意,覆盖 equals() 方法不是强制性的。覆盖看起来很简单,如果实现不当,那么带给程序的后果就不是降低性能这么简单了。类满足以下任意条件,建议不要覆盖 equals() 方法:
【实例】使用 toString() 方法将对象信息返回成字符串,代码如下:
注意,System.out.println() 就是调用类的 toString() 方法,如果类没有重写 toString(),那么调用的是父类 Object 的 toString() 方法;如果重写了,就按照重写的 toString() 规则组织对象信息文本。
在 Java 程序中,如果一个类没有显示声明继承某个类,就默认直接继承 Object 类。Object 类提供无参数构造方法,不提供有参数构造方法。虽然程序一般并不会直接调用 new Object(),但在子类对象实例化时都会默认调用父类中的无参数构造方法。
所有对象都能调用 Object 类中定义的公有方法,如 hashCode()、equals()、toString() 等。尽管 Object 类是一个具体类,但设计它的主要目的是拓展。下面对一些常用方法进行介绍。
Java hashCode()方法
hashCode() 是一个本地方法(native),Object 类中并没有对该方法具体实现,而是由 C/C++ 实现,Java 来调用。根据对象地址或其他信息,使用哈希算法计算出 int 类型的散列码。这个哈希值通常用于辅助 equals() 完成比较。注意,同一个对象多次调用 hashCode() 方法必须得到相等的散列码,但相同的散列码不能说明两个对象一定是同一个对象。
【实例 1】使用 hashCode() 方法判断两个对象是否是同一个对象,代码如下:
public class PersonDemo { private String id; private String name; private int age; public static void main(String[] args) { PersonDemo p1 = new PersonDemo(); PersonDemo p2 = new PersonDemo(); System.out.println("p1.hashCode() = " + p1.hashCode()); System.out.println("p1.hashCode() = " + p1.hashCode()); System.out.println("p2.hashCode() = " + p2.hashCode()); } }在上述代码中,可以实现相同的散列码,但不能说明两个对象一定是同一个对象。
Java equals()方法
equals() 方法用以确定两个对象是否相等。如果类未覆盖 equals() 方法(默认情况),那么 equals() 比较的是两个对象的引用地址是否相等,代码如下:public class Object { ... public boolean equals(Object obj) { return (this == obj); } }
【实例 2】使用 equals() 方法判断两个对象内容是否相等,代码如下:
import java.util.Objects; public class PersonDemo { private String id; private String name; private int age; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PersonDemo that = (PersonDemo) o; return age == that.age && Objects.equals(id, that.id) && Objects.equals(name, that.name); } @Override public int hashCode() { return Objects.hash(id, name, age); } }在上述代码中,程序调用 hashCode() 方法计算对象散列值:
若散列值不相等,则说明两个对象不是同一个对象;
若散列值相等,则需要进一步调用 equals() 方法判断。
逻辑说明如下:
if (this == object) return true;
若两个对象的引用地址相等,则返回 true 并结束后续判断 (x.equals(x));若引用地址不一致,则将进一步判断。
if (object == null || getClass() != object.getClass()) return false;对语法 x.equals(y) 来说,调用 equals 的对象 x 不能为 null,因为 null.equals(y) 本身不能通过编译,所以 x 一定不为 null。若 y 为 null,则直接返回 false;若 y 不为 null,则进一步判断类型;若 x 类型不等于 y 类型,则直接返回 false。
若类型也相同,则进一步做以下判断:
Person person = (Person) object; return age == person.age && Objects.equals(id, person.id) && Objects.equals(name, person.name);对语法 x.equals(y) 来说,将 y 转化为具体类型,若年龄、身份证号、姓名都相等,则返回 true。
覆盖 equals() 方法时应该同时覆盖 hashCode() 方法,因为相等的对象必须具有相同的散列码。
注意,覆盖 equals() 方法不是强制性的。覆盖看起来很简单,如果实现不当,那么带给程序的后果就不是降低性能这么简单了。类满足以下任意条件,建议不要覆盖 equals() 方法:
- 实例值受控的类。因为实例值受控的类可以确保“每个值至多只存在一个对象”,如枚举类型。
- 类不具有特定的“逻辑相等”概念。例如,上一节讲述正则表达式提到的 Pattern 类,覆盖 equals() 方法用于检查两个 Pattern 实例是否代表同一个对象。一般来说,逻辑并不需要这样的判断功能,使用 Object 类或父类提供的 equals() 方法就完全够用了。
- 类被私有化(private)或包级私有化(default)。此时,equals() 方法不会得到调用。
Java toString() 方法
toString() 是返回对象字符串表示的方法。该字符串由对象作为实例的类的名称、“@”符号字符和无符号的十六进制对象哈希代码组成,格式为“类全限定名@哈希值”。该字符串以文本方式表示,结果应该是信息丰富的简洁表示,便于代码阅读。所有类都应该重写此方法。【实例】使用 toString() 方法将对象信息返回成字符串,代码如下:
import java.util.Objects; public class PersonDemo { private String id; private String name; private int age; @Override public String toString() { return "PersonDemo{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; } }在上述代码中,使用 toString() 方法将对象信息返回成字符串。
注意,System.out.println() 就是调用类的 toString() 方法,如果类没有重写 toString(),那么调用的是父类 Object 的 toString() 方法;如果重写了,就按照重写的 toString() 规则组织对象信息文本。