Object源码分析

 
package java.lang;

/**
 * Class {@code Object} is the root of the class hierarchy.
 * Every class has {@code Object} as a superclass. All objects,
 * including arrays, implement the methods of this class.
 *
 * @author  unascribed
 * @see     java.lang.Class
 * @since   JDK1.0
 */
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 > 0) {
            timeout++;
        }

        wait(timeout);
    }
    public final void wait() throws InterruptedException {
        wait(0);
    }
    protected void finalize() throws Throwable { }
}
private static native void registerNatives()

该方法在java doc中并没有给出该方法详细的描述, 我就去google了一下, 在stackoverflow上找到了一个答案,What does the registerNatives() method do? ,看完这个解答一下, 谈一下我的理解.

  • 该方法会注册该类中的相关native方法.
  • 建立JNI方法和本地c++ 的”链接”, 也就是这个方法本身是由c++ 写的, 但能在java中进行调用, 就是建立这种调用关系.
  • 该方法在类加载完成之后, 进行生成实例之前, 在这之间就运行完成.

不仅仅Object类中会有registerNatives()方法这样的使用, 其他拥有本地方法的类(比如java.lang.Class, java.lang.Thread)也会这样做, 所以你如果需要调用自己的native方法, 就需要这样做.

public final native Class<?> getClass()

返回运行时所指向实例的具体类型. 在看到这个方法的时候, 我忽然有了一个”大胆的想法”, 然后我立马就实验了一下.

    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>();
        nums.add(1);
        Class<?> c = nums.get(0).getClass();
        System.out.println(c);
    }

结果输出

即使有java的泛型擦除机制, 也会显示出具体的运行时类型. 如果我按下面这样来写, 估计能给你更深的印象.

    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>();
        nums.add(1);
        Object num = nums.get(0);
        Class<?> c = num.getClass();
        System.out.println(c);
    }

输出的结果还是和上面一样

public native int hashCode()

返回对象的hashcode.

java doc中说明的hashcode准则:

The general contract of hashCode is: Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

总的来说,上面说的hashcode准则是:

  • 如果两个对象equals() 方法相等, 那么返回的hashcode是一定是相等的.
  • 如果两个对象equals()方法不相等, 那么返回的hashcode不一定是不相等的. (有可能相等, 有可能不等.)

如果equals()不相等, hashcode也不相等, 那么是否可以提升相关哈希容器的性能? —疑惑 可以在判断”复杂对象之前”先调用hashcode()之前进行比较, 如果不相等, 那么可以确定这两个对象不相等, 提前返回(&& fast fail), 如果通过再进行equals()方法比较.

public boolean equals(Object obj)

返回两个对象是否相等.

equals方法在非null对象引用上实现等价关系:

  • 自反性:对于任何非空引用值x,x.equals(x)应该返回true。
  • 对称性:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
  • 传递性:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true。
  • 一致性:对于任何非空引用值x和y,x.equals(y)的多次调用始终返回true或始终返回false,前提是不修改在对象的equals比较中使用的信息。
  • 对于任何非空引用值x,x.equals(null)应返回false。 类Object的equals方法实现了对象上最具辨别力的等价关系;也就是说,对于任何非空引用值x和y,当且仅当x和y引用同一对象时,此方法才返回true(x == y的值为true)。

Note:通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相等的哈希代码.

protected native Object clone() throws CloneNotSupportedException

返回一个对象的副本. 该对象必须实现Cloneable接口, 否则会抛出CloneNotSupportedException. 数组实现了Cloneable, 但是官方doc上说明返回的是浅拷贝的副本? (该方法不经常用, 就不先不深究)

public String toString()

返回对象的字符串表现形式. Object默认返回的是class的name(全名)和hashcode的十六进制形式

        Object o = new Object();
        System.out.println(o);

输出结果

public final native void notify()

唤醒一个等待该实例监视器(内置锁)的线程. 该方法必须由持有内置锁的线程进行 调用否则会抛出IllegalMonitorStateException

public final native void notifyAll()

唤醒所有正在等待实例监视器(内置锁)的线程. 调用线程必须和notify()的调用线程一致, 是持有内置锁的线程进行调用.

notify()notifyAll()方法的调用要根据情况, notifyAll()会将所有线程唤醒, 所有唤醒的线程将争夺锁, 这将造成性能的下降, 但是大部分的时候如果你并不是很清楚锁所维护的条件的时候, 那就使用notifyAll()吧, 这也是大部分的人的选择, 因为这不会造成死锁. 但是如果你对性能有严格的要求,认为notifyAll()不满足, 而notify()也不适合, 那么就用concurrent的显示锁吧.

public final native void wait(long timeout) throws InterruptedException

当前线程进入该实例内置锁的等待队列, 直接其他线程调用notify()或者notifyAll(), 或者超过了指定的等待时间. 当前线程必须持有内置锁才能调用wait(). 如果该线程被其他线程调用了interrupted(), 一个InterruptedException将会”准备”抛出, 只有当该线程持有内置锁的时候, 才会抛出.

public final void wait(long timeout, int nanos) throws InterruptedException

wait()方法的重载版本.

public final void wait() throws InterruptedException

wait()方法的重载版本.

protected void finalize() throws Throwable { }

当垃圾回收器确定可以回收该对象之后, 会调用该方法.