Java漫游笔记-03-03-Object类

Object 类是所有类的超类。
所有对象(包括数组)都实现这个类的方法。
因此我们很有必要了解一下它。

equals()

Objectequals() 是直接比较两个对象的引用是否相同。

如果需要判断对象的属性值是否相等,需要覆盖这个方法。
除了 Stringequals() 很常见以外,其实还有很多地方,都可能会用到 equals() ,例如,在集合类中的 contains(Object)remove(Object) 都用到了: (o==null ? e==null : o.equals(e))

覆盖 equals() 需要注意的是,需要满足以下条件:

  • 自反性:x.equals(x) 返回 true
  • 对称性:若 x.equals(y)true ,则 y.equals(x) 亦为 true
  • 传递性:若 x.equals(y)truey.equals(z) 也为 true ,则 x.equals(z) 亦为 true
  • 一致性:x.equals(y) 的第一次调用为 true ,那么 x.equals(y) 的第 2 次、第 3 次、第 n 次调用也均为 true ,前提条件是没有修改 x 也没有修改 y;
  • 对于非空引用 x ,x.equals(null) 返回为 false

常见的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public boolean equals(Object obj) {
// 判断引用是否相等
if (this == obj) {
return true;
}
// 如果是 null 的情况
if (obj == null) {
return false;
}
// 判断类型是否一致,如果子类也允许相等,可以考虑使用 instanceof
if (getClass() != obj.getClass()) {
return false;
}
Person other = (Person) obj;
// 比较属性值是否相等
if (age != other.age) {
return false;
}
return true;
}

hashCode()

有一些基于 Hash 算法的数据结构(例如:HashMapHashSet )需要用到这个方法。

散列值并没有什么实际含义,只是用来标记对象的
因为不同对象的散列值一般不同(但并不是绝对的)。

如果覆盖了 equals() ,那么一般也要覆盖 hashCode() ,以便于用户可以正确地将对象插入到散列表。
并且, hashCode() 返回的值应该能够尽量地离散分布。

toString()

ObjecttoString() 直接输出对象的类名和散列码。
没有什么实际用处,一般都需要覆盖。

当我们调用 System.out.println(x) 的时候,实际上相当于 System.out.println(x.toString())

clone()

关于对象的克隆,有浅克隆深克隆之分。
浅克隆,只会克隆一层,如果被克隆的对象的属性是一个引用,那么这个引用还是指向原来的对象,如果这个属性,是不可变的(例如:StringIntegerLong ),那么不会与什么问题,否则,这样的共享,往往是会带来问题的,需要注意。

Object 类的 clone() 方法属于浅克隆,还是 protected 方法。

实现深克隆的类,需要:

  • 实现 Cloneable 接口(建议需要浅克隆时,也声明这个接口)。
  • 覆盖 Objectclone() 方法,并使用 public 修饰。
  • 克隆该对象所有可变的属性。

wait()

调用 wait() 方法,会使当前线程立即释放在此对象上的锁,从而进入等待状态,直至被 notify() 方法或 notifyAll() 方法唤醒。

需要注意的是,wait() 必须在同步方法或代码块中调用

notify() 和 notifyAll()

notify() 是唤醒在此对象监视器上等待的单个线程,但仅仅只是起到一个通知的作用,不释放锁,也不获取锁。如果所有线程都在此对象上等待,会随机选择唤醒其中一个线程。

notifyAll() 则是唤醒在此对象监视器上等待的所有线程。

同样的,notify()notifyAll() 也必须在同步方法或代码块中调用

finalize()

当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用 finalize() 方法。
这个方法的设计初衷应该是,想让开发者能够在垃圾回收之前做一些善后的工作。
然而,事实上,我们无法确定这个方法究竟什么时候会被调用。因此,不可靠,不要使用它

Objects类

另外,JDK 1.7 还新增了 java.util.Objects 类,它提供了对象检查和处理 hash 等操作的静态方法,例如:

  • equals(Object a, Object b)
  • deepEquals(Object a, Object b)
  • isNull(Object obj)
  • nonNull(Object obj)
  • requireNonNull(T obj, String message)
  • hashCode(Object o)
  • hash(Object… values)

附: Object 类的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package java.lang;
public class Object {

private static native void registerNatives();

static {
registerNatives();
}

public final native Class<?> getClass();

public native int hashCode();

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

protected native Object clone() throws CloneNotSupportedException;

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

public final native void notify();

public final native void notifyAll();

public final native void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}

if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}

wait(timeout);
}

public final void wait() throws InterruptedException {
wait(0);
}

protected void finalize() throws Throwable {
}
}