看Java API的Object类, 一共11个方法。按使用的频度排名:

  1. toString() 这个方法最常用在打日志,定位代码问题。

  2. equals()hashCode(), 这两个方法的使用经典例子是HashMap的源码

 public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; } 

equals()hashCode() 要常用一点。

  1. wait()notify() 这个开发很少会直接用到,但是间接用到的场景不少,属于偏内功的点。wait/notify属于Object类最难理解的点了,因为它的基石是多线程。学习思路还是三步走。

step 1: 看文档说明

wait() Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. notify() Wakes up a single thread that is waiting on this object's monitor. 

这个文档说明,看完基本一头雾水,两个方法都提到了如下的核心概念thread, object's monitor。 先把这些概念放一边,看看是怎么用的。

step 2: 运行Demo

给个demo辅助理解,一个线程是干活的,另一个线程是管事的。管事的等活干完验收。

public class WaitNotifyDemo { static class Worker extends Thread{ private volatile int status=0; // 1: 完成, -1: 出错 @Override public void run(){ try { System.out.println(Thread.currentThread().getName() +": 开始干活"); Thread.sleep(3000); System.out.println(Thread.currentThread().getName() +": 完成任务"); status = 1; // 通知主线程 synchronized (this){ this.notify(); } } catch (InterruptedException e) { e.printStackTrace(); status = -1; } } public int getStatus(){ return status; } } public static void main(String[] args) throws InterruptedException { Worker worker= new Worker(); worker.start(); synchronized (worker){ int status; while ((status=worker.getStatus())!=1){ worker.wait(); if(status==-1) throw new RuntimeException("出错了"); } } System.out.println("任务已经完成"); } } 

step3: 折腾demo 接下来, 我试了一下, 把notify的代码去掉,也能正常运行。 这就让人困惑了,文档明明说必须调用notify,wait才能结束。接下来再看文档:

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup 

所以, wait方法必须在while循环中调用。好,解答了一点疑惑。但是每次Worker线程结束时没有调用notify,主线程就能正常退出, 这个也说不通。 唯一的解释是: JVM内部在某个地方调用了notify。看openjdk的源码, 果然如此:从start0开始, 定位到线程在退出时会调用lock.notify_all(thread);。只是这里的代码是JVM内部的代码,比较底层。

其实,这个例子更简洁的写法是worker.join()。 如果看Thread.join()的源码,发现它的实现恰好就是调用了wait。

  1. clone() 这个需要理解深度克隆, 知识点不复杂。

  2. getclass() 这个放在后面,但是用得还挺多的,特别是写框架。

  3. finalize() 这个已经不他推荐使用了, 尽量不干扰GC的节奏。

总结一下,Object类是Java的基石。这里比较难一点的就是wait/notify. 学习Java的API, 如果想理解透彻一点,估计绕不开JVM的c++源码。