Java源码分析—Object

Java源码分析—Object

本文的分析基于JDK 1.8

1.static native void registerNatives()

private static native void registerNatives();
static {
registerNatives();
}

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

2. native Class<?> getClass()

这也是一个本地方法,返回一个对象的运行时类。返回运行时的实际类型

3. native int hashCode()

这也是一个本地方法,返回值是对象的一个哈希值。
在编写实现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

从这里我们可以看到,equals(obj)方法最根本的实现就是‘==’,因此对于一些自定义类,如果没有重写hashcode()方法和equals()方法的话,利用‘==’和equals()方法比较的结果是一样的。对于‘==’比较的是地址,equals()方法比较的是内容这种说法,是片面的。(虽然在最常用的String类中是这样的)。
对equals重新需要注意五点:
1. 自反性:对任意引用值X,x.equals(x)的返回值一定为true;
2. 对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
3. 传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true ;
4. 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变;
5. 非空性:任何非空的引用值X,x.equals(null)的返回值一定为false 。

5. native Object clone()

protected native Object clone() throws CloneNotSupportedException;
   
   
  • 1

这个也是本地方法。需要注意的是该方法是“浅拷贝”的。
浅拷贝:如果一个对象内部还有一个引用类型的基本变量,那么再拷贝该对象的时候,只是在通过clone方法新产生的新对象中拷贝一个该基本类型的引用。换句话说,也就是新对象和原对象他们内部都含有一个指向同一对象的引用。
深拷贝:拷贝对象的时候,如果对象内部含有一个引用类型类型的变量,那么就会再将该引用类型的变量指向的对象复制一份,然后引用该新对象。
下面2个图可以帮助理解:
深拷贝与浅拷贝
Java源码分析—Object

6. String toString()

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

此方法返回对象的字符串描述,子类重写此方法

7.void notify()notifyAll()方法

public final native void notify();
public final native void notifyAll();
   
   
  • 1
  • 2

这2个方法都是本地方法,前者唤醒一个在当前对象监视器上等待的线程。后者唤醒所有在当前对象监视器上等待的线程。
我们应该注意的是,这2个方法应当仅仅被拥有对象监视器的线程所调用。而一个线程成为对象的监视器的拥有者有三种方法:
- 执行该对象上的一个同步(synchronized)方法
- 执行一个同步在在对象上的代码块
- 执行该对象的类上的静态同步方法

8.void wait(long timeout); void wait(long timeout,int nanos); void wait();

本地方法。 
首先,调用该方法会抛出中断异常(InterruptedException),调用时应该用try catch捕捉。
 - public final native void wait(long timeout) throws InterruptedException;
本地方法 
该方法也会抛出中断异常,调用时应捕捉。
该方法使当前线程等待,直到另外一个线程调用该对象的notify或notifyAll方法,或者等待时间已到,当前线程才会从等待池移到运行池。 
如果在wait之前或者wait的时候,当前线程被中断了,那么直到该线程被恢复的时候才会抛出中断异常(InterruptedException)。
 - public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
    <span class="hljs-keyword">if</span> (nanos &lt; <span class="hljs-number">0</span> || nanos &gt; <span class="hljs-number">999999</span>) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(
                            <span class="hljs-string">"nanosecond timeout value out of range"</span>);
    }

    <span class="hljs-keyword">if</span> (nanos &gt; <span class="hljs-number">0</span>) {
        timeout++;
    }

    wait(timeout);
}

该方法可能会抛出中断异常,调用时应捕捉。源码只是将timeout四舍五入,并没有提供更高精度的控制。

  • <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">wait</span>() <span class="hljs-keyword">throws</span> InterruptedException {
     wait(<span class="hljs-number">0</span>);
    
    }
    • 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

9.void finalize();

 - protected void finalize() throws Throwable { }
 - 
 
 
  • 1
  • 2

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

总结

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

上一篇:nginx backup 功能


下一篇:节流,防抖