0%

Java笔记-(2)Object类

Object类是Java中所有类的基类。定义的任何类都会默认继承Object类。Object类中有一系列重要的方法。

1. getClass

1
public final native Class<?> getClass();

返回该对象运行时类的Class对象。Class对象记录了类的信息,包括属性、方法。被 static synchronized 修饰的方法锁住的即为该对象。

2. hashCode

1
public native int hashCode();

返回该对象的一个hash值,该方法支持着各类哈希表的实现,如 HashMap

Object对该方法的默认实现是将对象的内部地址转换为一个整形值。

该方法的重写约定包括:

  1. Java应用程序执行期间多次对同一个对象调用 hashCode 方法时,只要没有修改在对象 equals 方法比较中使用的信息,该方法就必须一致地返回相同的整数。但不要求同一应用程序在不同的执行中返回相同的值。
  2. 若根据 equals(Object) 方法得到两个对象相等,则两个对象的 hashCode 需要返回相同的值。
  3. 若根据 equals(Object) 方法得到两个对象不相等,并不要求两个对象的 hashCode 一定要返回不同的值。但设计时最好降低二者 hashCode 返回相同值的概率,这样可以提高哈希表的性能。

3. equals

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

返回某个对象是否和当前对象“相等”。该方法实现了一个非空对象引用的等级关系。即

  1. 自反性:对于任何非空引用 xx.equals(x) 始终为true
  2. 对称性:对于任何非空引用 xx.equals(y)y.equals(x) 同真假
  3. 传递性:对于任何非空引用 x ,若 x.equals(y)y.equals(z) 为true,则 x.equals(z) 为true
  4. 一致性:对于任何非空引用 x ,假设 equals 方法中用到的信息不被修改,则对 x.equals(y) 的多次调用应始终返回相同的值
  5. 对于任何非空引用 xx.equals(null) 应始终返回false

4. clone

1
protected native Object clone() throws CloneNotSupportedException;

返回当前对象的一个拷贝对象。若类未实现 Clonealbe 接口会抛出 CloneNotSupportedException ,否则返回当前对象的一个浅拷贝,即新建一个对象,并简单地将当前对象所有属性的值赋给新对象。此外,所有数组类型 T[] 默认实现了 Clonealbe 接口,无论 T 是基本类型还是引用类型。

5. toString

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

返回当前对象的字符串表示。建议在所有子类中重写它。

6. notify

1
public final native void notify();

唤醒等待该对象monitor的一个线程。若有多个线程在等待,则会选择其中一个。选择是任意的,由实现自行决定。

在当前线程释放该对象的monitor之前,被唤醒的线程将无法继续执行。

调用该方法的线程必须持有当前对象的monitor(🔒)

一个线程可以通过三种方式获取对象的monitor。

  1. 通过执行一个对象的由 synchronized 修饰的实例方法
  2. 通过执行被 synchronized 修饰的代码块,且 synchronized 锁住的是当前对象
  3. 对于Class类对象,通过执行该类被 static synchronized 修饰的方法

一个对象的monitor在一个时刻只能被一个线程持有。

7. notifyAll

1
public final native void notifyAll();

唤醒所有等待该对象monitor的线程。

调用该方法的线程必须持有当前对象的monitor(🔒)

8. wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public final native void wait(long timeoutMillis) throws InterruptedException;

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

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

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

if (nanos > 0 && timeoutMillis < Long.MAX_VALUE) {
timeoutMillis++;
}

wait(timeoutMillis);
}

使当前对象所在的线程进入等待状态,直到其他线程调用该对象的 notifynotifyAll 方法,或等待指定的时间。

调用该方法的线程必须持有当前对象的monitor(🔒)。

该方法会使当前线程将自身加入对象的等待集,然后放弃此对象上的任何同步声明。在以下四种情况发生前,当前线程将保持休眠,不参与线程调度。

  1. 其他线程调用对象的 notify 方法且当前线程正好被选中唤醒
  2. 其他线程调用对象的 notifyAll 的方法
  3. 其他线程调用当前线程的 interrupt 方法
  4. 经过指定的等待时间。若指定时间为0,则表示等待无限长时间,只能被其他三种方法唤醒。

达到触发条件后,当前线程将从对象的等待集中移除,并重新参与线程调度以及和其他线程对该对象的竞争。

注意,当wait方法将当前线程放入该对象的等待集时,它只解锁该对象。在线程等待时,当前线程上可能被同步的任何其他对象将保持锁定。

9. finalize

1
protected void finalize() throws Throwable { }

当垃圾收集确定没有对对象的更多引用时,由垃圾收集器在对象上调用。子类可以重写finalize方法来释放系统资源或执行其他清理。

finalize 方法中可以采取任何措施,包括使该对象再次对其他线程可用。但通常情况下,finalize 方法的作用是在该对象被无法恢复地销毁前执行一些清除操作,例如释放一些非Java资源(打开的文件、数据库连接)或调用非Java方法时分配的内存(C的malloc)。由于GC的不确定性,finalize 的调用时机也是不确定的。即,从一个对象变得不可达,到其 finalize 方法被调用,这期间经历的时间不确定,因此不要过于依赖 finalize 来完成资源回收,很可能在 finalize 被调用前资源就已耗尽。最好的方法是当不再需要分配给对象的资源时,在业务代码中就进行释放操作。

Java不能保证由哪个线程来调用给定对象的 finalize 方法。但可以保证的是,在调用 finalize 时,调用线程将不持有任何用户可见的同步锁。如果 finalize 方法抛出未捕获的异常,则该异常将被忽略,并且该对象的终结将终止。

finalize 方法最多只会被调用一次。

Object对象的 finalize 方法不执行任何特殊操作,它只是正常返回。Object的子类可以重写该方法。