我看JAVA 之 Object & JNI

我看JAVA 之 Object & JNI

注:基於jdk11

Object

Object類是java語言中所有類的父類。


public class Object {
    //註冊本地函數,方可以從庫中的本機代碼調用JNI函數
    private static native void registerNatives();
    static {
        registerNatives();
    }

    /**
     * Constructs a new object.
     */ 
    //HotSpotIntrinsicCandidate註解,說明本方法,jvm額外維護了一個利用了CPU指令的高效實現
    @HotSpotIntrinsicCandidate
    public Object() {}

    //返回對象的運行時類型
    /**
     * Number c = 0;
     * Class<? extends  Number> clazz = c.getClass();
     * System.out.println(clazz);
     * 打印如下:
     * class java.lang.Integer
     * 關於泛型及泛型擦除概念,見後續泛型章節
     */
    @HotSpotIntrinsicCandidate
    public final native Class<?> getClass();

     /**
     * 返回對象的hash碼,hashCode方法支持hash表(比如java.util.HashMap)的特性,
     * 不同的對象返回唯一的has碼,可以提高hash表數據結構的性能。
     * hashCode有時候以對象內存地址的機制生成,有時候不是
     * java.lang.System.identityHashCode 工具方法 返回默認hashCode()方法的值,null引用返回的hash碼爲0
     */ 
    @HotSpotIntrinsicCandidate
    public native int hashCode();

    /**
    * 標示其他對象與當前對象是否相等
    * 自反性: 自己(非null)與自己比較永遠相當
    * 對稱性: x vs y or y vs x 等價
    * 可傳遞: x.equals(y) == true and y.equals(z), then x.equals(z)
    * 一致性: 一旦x.equals(y) == true, then anytime x.equals(y) == true
    * any not null value not equals null
    * 如果覆蓋equals方法,一定要覆蓋hashCode方法
    */
    public boolean equals(Object obj) {
        return (this == obj);
    }

    /**
     * clone返回會返回一個相同類型的新對象拷貝,如果要實現克隆,那麼當前類及其父類需要實現cloneable接口。
     * 對於複雜類型,默認的clone方式僅實現”淺克隆”,如果要實現”深克隆”,需要覆蓋clone方法。
     * 注:在軟件編程中,推薦使用工具類的方式做copy,而不是覆蓋clone的方式
          */
    @HotSpotIntrinsicCandidate
    protected native Object clone() throws CloneNotSupportedException;

    /**
    * 默認返回 getClass().getName() + '@' + Integer.toHexString(hashCode())
    * 具體類可以覆蓋Object的toString()方法
    */
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    /**
     * 持有該對象鎖的線程通過調用notify喚醒等待此對象監視器的某一個線程,選擇是隨機的(具體由不同虛擬機實現)。一次只能有一個線程持有對象鎖。
     * 獲取對象鎖定三種方式如下:
     * 1,通過執行該對象的同步實例方法
     * 2,通過執行該對象的同步代碼塊
     * 3,通過執行類的同步靜態方法
     * 見 /openjdk/hotspot/src/share/vm/prims/jvm.cpp line: 526~530
     * 見 /openjdk/hotspot/src/share/vm/runtime/synchronizer.cpp line: 407~411
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of this object's monitor.
     * @see        java.lang.Object#notifyAll()
     * @see        java.lang.Object#wait()
     */
    @HotSpotIntrinsicCandidate
    public final native void notify();

    /**
     * 持有該對象鎖的線程通過調用notify喚醒等待此對象監視器的所有線程。噹噹前線程釋放對象監視器後,其他喚醒的線程會競爭對象監視器。
     *
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of this object's monitor.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#wait()
     */
    @HotSpotIntrinsicCandidate
    public final native void notifyAll();

    /**
     * 調用此方法會導致當前對象進入等待狀態,知道被其他線程喚醒(notify)或中斷(InterruptedException)。相當於wait(0L)
     *
     * @throws IllegalMonitorStateException if the current thread is not
     *         the owner of the object's monitor
     * @throws InterruptedException if any thread interrupted the current thread before or
     *         while the current thread was waiting. The <em>interrupted status</em> of the
     *         current thread is cleared when this exception is thrown.
     * @see    #notify()
     * @see    #notifyAll()
     * @see    #wait(long)
     * @see    #wait(long, int)
     */
    public final void wait() throws InterruptedException {
        wait(0L);
    }

    /**
     * 
     * @param  timeoutMillis the maximum time to wait, in milliseconds
     * @throws IllegalArgumentException if {@code timeoutMillis} is negative
     * @throws IllegalMonitorStateException if the current thread is not
     *         the owner of the object's monitor
     * @throws InterruptedException if any thread interrupted the current thread before or
     *         while the current thread was waiting. The <em>interrupted status</em> of the
     *         current thread is cleared when this exception is thrown.
     * @see    #notify()
     * @see    #notifyAll()
     * @see    #wait()
     * @see    #wait(long, int)
     */
    public final native void wait(long timeoutMillis) throws InterruptedException;

    /**
     *  在併發編程章節重點講解
     * @param  timeoutMillis the maximum time to wait, in milliseconds
     * @param  nanos   additional time, in nanoseconds, in the range range 0-999999 inclusive
     * @throws IllegalArgumentException if {@code timeoutMillis} is negative,
     *         or if the value of {@code nanos} is out of range
     * @throws IllegalMonitorStateException if the current thread is not
     *         the owner of the object's monitor
     * @throws InterruptedException if any thread interrupted the current thread before or
     *         while the current thread was waiting. The <em>interrupted status</em> of the
     *         current thread is cleared when this exception is thrown.
     * @see    #notify()
     * @see    #notifyAll()
     * @see    #wait()
     * @see    #wait(long)
     */
    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++;
        }

        wait(timeoutMillis);
    }

    /**
     * 通知垃圾回收器當前對應已經沒有引用了,具體回收還要看jvm內部實現。
     * jdk9 標記位過時,在jvm原理章節重點講解
     *
     * @throws Throwable the {@code Exception} raised by this method
     * @see java.lang.ref.WeakReference
     * @see java.lang.ref.PhantomReference
     * @jls 12.6 Finalization of Class Instances
     */
    @Deprecated(since="9")
    protected void finalize() throws Throwable { }
}

JNI(Java Native Interface)

java本地接口,意爲JAVA語言提供一套規範供操作系統底層實現,一般是C/C++語言,不同操作系統版本的jvm提供了相應的實現,以達到"Write Once Run Anywhere“

實現JNI大致步驟如下

  1. 定義java程序

    package chapter01;
    
    public class TestJNI {
    
        public native void hello();//所有native關鍵詞修飾的都是對本地的聲明
        static {
            System.loadLibrary("hello");//載入本地庫
        }
        public static void main(String[] args) {
            new TestJNI().hello();
        }
    }
  2. 編譯javac chapter01/TestJNI.java,生成TestJNI.class
  3. 執行javac chapter01/TestJNI.java -h . ,生成JAVA本地接口chapter01_TestJNI.h

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class chapter01_TestJNI */
    
    #ifndef _Included_chapter01_TestJNI
    #define _Included_chapter01_TestJNI
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     chapter01_TestJNI
     * Method:    hello
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_chapter01_TestJNI_hello
      (JNIEnv *, jobject);
    
    #ifdef __cplusplus
    }
    #endif
    #endif

    注意:JNIEnv、 jobject等類型都是在jni.h頭文件中定義的,所以需要include jni.h

  4. 編寫步驟3的接口實現,創建TestJNIImpl.c

    #include "jni.h"
    #include "chapter01_TestJNI.h"
     
    //#include otherheaders
     
    JNIEXPORT void JNICALL
    Java_chapter01_TestJNI_hello(JNIEnv *env, jobject obj)
    {
        printf("Helloworld!\n");
        return;
    }
  5. 將本地方法編寫的文件生成動態鏈接庫
    gcc -dynamiclib -I /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/include TestJNIImpl.c -o libhello.jnilib
    注意:如果/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/include不存在jni_md.h的話,可以從 /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/include/darwin 拷貝過來
  6. 執行java程序 java -Djava.library.path=/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/include chapter01/TestJNI
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章