本文的分析基于JDK 1.8 
Java中所有的类都继承自Object类。

Object类的源码解析

1.void registerNatives()

   private static native void registerNatives();
    static {
        registerNatives();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

该方法只是对几个本地方法进行注册(即初始化java方法映射到C的方法)。需要注意的是,很多类中都有这个方法,但是执行注册的目标是不同的。System类中也有该方法,但是它注册的方法是另一些方法。

2.Class <?> getClass()方法

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

这也是一个本地方法,返回一个对象的运行时类。注意是运行时类。请看下列代码:


public class tests
{
    public static void main(String[] args)
    {
        A te = new B();
        System.out.println(te.getClass());
    }
}
class A{

}
class B extends A
{

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

运行结果是:

class B
  • 1
  • 2
  • 1
  • 2

A类的引用,但是运行时te这个对象的实际类是B。

3.int hashCode()方法

public native int hashCode();
  • 1
  • 1

这也是一个本地方法,返回值是对象的一个哈希值。 
在编写实现hashCode()方法时,我们需要遵守一些约定:

  • 在应用程序执行期间,如果一个对象用于equals()方法的属性没有被修改的话,那么要保证对该对象多次返回的hashcode值要相等。
  • 如果2个对象通过equals()方法判断的结果为true,那么要保证二者的hashcode值相等。
  • 如果2个对象通过equals()方法判断的结果为false,那么对二者hashcode值是否相等并没有明确要求。如果不相等,那么能够提升散列表的性能。

4.boolean equals(Object obj)

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

从这里我们可以看到,equals(obj)方法最根本的实现就是‘==’,因此对于一些自定义类,如果没有重写hashcode()方法和equals()方法的话,利用‘==’和equals()方法比较的结果是一样的。对于‘==’比较的是地址,equals()方法比较的是内容这种说法,是片面的。(虽然在最常用的String类中是这样的)。

5.Object clone()

protected native Object clone() throws CloneNotSupportedException;
  • 1
  • 1

这个也是本地方法。需要注意的是该方法是“浅拷贝”的。

  • 浅拷贝:如果一个对象内部还有一个引用类型的基本变量,那么再拷贝该对象的时候,只是在通过clone方法新产生的新对象中拷贝一个该基本类型的引用。换句话说,也就是新对象和原对象他们内部都含有一个指向同一对象的引用。
  • 深拷贝:拷贝对象的时候,如果对象内部含有一个引用类型类型的变量,那么就会再将该引用类型的变量指向的对象复制一份,然后引用该新对象。

下面2个图可以帮助理解:

深拷贝与浅拷贝

6.String toString()方法

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

很简单,就是返回信息而已。该方法经常被重写。

7.final void notify()方法和final void notifyAll()方法

这2个方法都是本地方法,前者唤醒一个当前对象监视器上等待的线程。后者唤醒所有当前对象监视器上等待的线程。 
我们应该注意的是,这2个方法应当仅仅被拥有对象监视器的线程所调用。而一个线程成为对象的监视器的拥有者有三种方法:

  • 执行该对象上的一个同步(synchronized)方法
  • 执行一个同步在在对象上的代码块
  • 执行该对象的类上的静态同步方法
    public final native void notify();
    public final native void notifyAll();
  • 1
  • 2
  • 1
  • 2

8.final native void wait()方法

本地方法。 
首先,调用该方法会抛出中断异常(InterruptedException),调用时应该用try catch捕捉。

    public final void wait() throws InterruptedException {
        wait(0);//0表示没有时间限制。
    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

9.final native void wait(long timeout)

本地方法 
该方法也会抛出中断异常,调用时应捕捉。

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

该方法使当前线程等待,直到另外一个线程调用该对象的notify或notifyAll方法,或者等待时间已到,当前线程才会从等待池移到运行池。 
如果在wait之前或者wait的时候,当前线程被中断了,那么直到该线程被恢复的时候才会抛出中断异常(InterruptedException)。

10.final void wait(long timeout,int nanos)

该方法可能会抛出中断异常,调用时应捕捉。

    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 > 0) {
            timeout++;
        }

        wait(timeout);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

源码只是将timeout四舍五入,并没有提供更高精度的控制。

11.protected void finalize()方法

垃圾回收器在认为该对象是垃圾对象的时候会调用该方法。子类可以通过重写该方法来达到资源释放的目的。 
在方法调用过程中出现的异常会被忽略且方法调用会被终止。 
任何对象的该方法只会被调用一次。

总结

    • 本地方法有:除了equal()、wait()、wait(long timeout,long nanos)和toString()方法其余均是本地方法。
    • equals()方法经常被重写,而在重写的时候,hashcode()方法应当也重写。例如:当用equals()方法判断对象内容一致的时候,如果hashcode()方法没有重写而导致使用该方法得到的哈希值不同,这样就会产生歧义(比如在Set集合中是通过对象的hashcode值来“辨别”对象的,如果对象内容一致,hashcode值却不一致,会在使用Set集合操作时产生歧义)。(其实我感觉这应该就是制定编写hashcode()方法需要遵守那几个规范的原因)