Java Object
Object 类的方法、equals 与 hashCode 的约定、toString 与 getClass。
Object 类的方法
Object is the root of every class, defining equals, hashCode, toString, getClass, clone and finalize. Subclasses override as needed, but getClass is final.
| Method | Purpose |
|---|---|
| equals(Object) | Logical equality, default is == |
| hashCode() | Hash bucket index |
| toString() | Text representation |
| getClass() | Runtime class (final) |
| clone() | Shallow copy |
equals 与 hashCode
Contract: if a.equals(b) then their hash codes must match. Overriding equals alone makes objects unfindable in HashMap / HashSet, since they land in different buckets.
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point p)) return false;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
public class EqualsHash {
public static void main(String[] args) {
Point a = new Point(1, 2);
Point b = new Point(1, 2);
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(a.hashCode() == b.hashCode());
Set<Point> set = new HashSet<>();
set.add(a);
set.add(b);
System.out.println(set.size());
}
}false
true
true
1toString 与 getClass
Without overriding toString you get ClassName@hexhash, useless in logs. Override it and both println and logging show something meaningful.
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name=" + name + ", age=" + age + "}";
}
}
public class ToStringDemo {
public static void main(String[] args) {
User u = new User("Tom", 20);
System.out.println(u);
System.out.println(u.getClass().getSimpleName());
System.out.println(u.getClass() == User.class);
}
}User{name=Tom, age=20}
User
trueObject 类的方法
Object 是所有类的父类,定义了 equals、hashCode、toString、getClass、clone、finalize 等方法。子类按需重写,但 getClass 是 final 不能改。
| 方法 | 作用 |
|---|---|
| equals(Object) | 逻辑相等,默认比较地址 |
| hashCode() | 哈希桶下标 |
| toString() | 文本表示 |
| getClass() | 运行时类(final) |
| clone() | 浅拷贝 |
equals 与 hashCode
约定:a.equals(b) 为真则 a.hashCode() == b.hashCode() 必须成立。只重写 equals 会让对象放进 HashMap / HashSet 后查不到 —— 因为两者落在不同的桶里。
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point p)) return false;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
public class EqualsHash {
public static void main(String[] args) {
Point a = new Point(1, 2);
Point b = new Point(1, 2);
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(a.hashCode() == b.hashCode());
Set<Point> set = new HashSet<>();
set.add(a);
set.add(b);
System.out.println(set.size());
}
}false
true
true
1toString 与 getClass
不重写 toString 时打印的是 类名@十六进制哈希,对排查问题毫无帮助。重写后 println 和日志都能直接看到有意义的内容。
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name=" + name + ", age=" + age + "}";
}
}
public class ToStringDemo {
public static void main(String[] args) {
User u = new User("Tom", 20);
System.out.println(u);
System.out.println(u.getClass().getSimpleName());
System.out.println(u.getClass() == User.class);
}
}User{name=Tom, age=20}
User
true