1. 程式人生 > >Java JDK原始碼解析之:native方法

Java JDK原始碼解析之:native方法

初次看見native關鍵字是自己在看Scanner類原始碼中傳遞System.in引數實現列印,之後轉到System觀看原始碼時看見native關鍵字,關於native關鍵字筆者表示,是Java與C語言的通訊介面,因為Java語言沒有操作底層的條件,所以Java語言只好用C語言來操作底層部件,定義了native關鍵字。 System出現的native方法:

public final class System {
    private static native void registerNatives();
    .......
    }

筆者觀看程式碼時一臉懵,開始認為怎麼會有這種方法,沒有方法體。之後筆者也試了以下。順便搜尋一些前者資料。自己實現了一個。基於native關鍵字的加減法。

package com.java.jvm.demo;


public class JVMDemo {	
	

		public native int add(int i,int j);
		public native int sub(int i,int j);
		public native int mul(int i,int j);
		public native int div(int i,int j);
}

因為native關鍵字時要用C去實現的方法,在編譯時尤其注意,需要將類編譯成C語言的標頭檔案。

1、首先將類編譯為.class的位元組碼檔案 2、第一種方法是在.class的目錄下使用javah命令編譯,還有一種方法是在eclipse中配置編譯器。具體就不詳細說明。 3、類與包名一旦定義好不能隨意更改,因為編譯好的標頭檔案會附帶包、類名

之後編譯的標頭檔案程式碼:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_java_jvm_demo_JVMDemo */

#ifndef _Included_com_java_jvm_demo_JVMDemo
#define _Included_com_java_jvm_demo_JVMDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_add
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    sub
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_sub
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    mul
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_mul
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    div
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_div
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

直接使用#include 去引用標頭檔案編譯時肯定會報錯,因為C語言解釋不了這個標頭檔案,所以需要去Java JDK中尋找這個標頭檔案直譯器,標頭檔案直譯器在Java JDK安裝目錄:

D:\Program Files (x86)\Java\jdk1.7.0_72\include\jni.h D:\Program Files (x86)\Java\jdk1.7.0_72\include\win32\jawt_md.h D:\Program Files (x86)\Java\jdk1.7.0_72\include\win32\jni_md.h

將這三個檔案複製在VC標頭檔案庫中,VC的標頭檔案庫位於VC的安裝目錄下:

D:\softwere\Microsoft Visual Studio\VC98\Include

將三個標頭檔案直譯器放入這裡面之後,就可以進行元件.dll動態連結庫了。然後編寫的C語言原始碼:

#include "stdafx.h"
#include "jni.h"
#include "com_java_jvm_demo_JVMDemo.h"

JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_add
(JNIEnv *en, jobject obj, jint x, jint y)
{
	printf("hello welcome to add method ! \n");
	return (x+y);
}

/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    sub
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_sub
(JNIEnv *en, jobject obj, jint x, jint y)
{
	return (x-y);
}

/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    mul
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_mul
(JNIEnv *en, jobject obj, jint x, jint y)
{
	return (x*y);
}

/*
 * Class:     com_java_jvm_demo_JVMDemo
 * Method:    div
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_java_jvm_demo_JVMDemo_div
(JNIEnv *en, jobject obj, jint x, jint y)
{
	return (x/y);
}

注意:

1、C語言編譯不能是debug版本,需要轉換為Release版本 2、如果C語言編譯器32位,那麼Java必須是32位,不然丟擲UnsatisfiedLinkError異常:32 bit …amd 64等解釋異常。

編譯成功之後 jni.dll

拿到.dll檔案複製在java專案中:

複製.dll檔案 之後執行是不可能的,這輩子都不能,還需要配置一個Java的 Native library location 配置Native library location

測試:

package com.java.jvm.demo;

public class Demo {
	static{
		System.loadLibrary("jni");
	}
	
		public static void main(String[] args) {
			//Scanner
			//System
			JVMDemo demo = new JVMDemo();
			try {
				int a = demo.add(2, 3);
				int s = demo.sub(3, 2);
				int m = demo.mul(2, 3);
				int d = demo.div(4, 2);
				System.out.println("method add() = " + a);
				System.out.println("method sub() = " + s);
				System.out.println("method mul() = " + m);
				System.out.println("method div() = " + d);
			} catch (UnsatisfiedLinkError e) {
				// TODO: handle exception
				e.printStackTrace();
			}
		}

}

執行結果: 測試結果

總結:每次檢視JDK原始碼時候,總是能重新整理自己對Java語言的世界觀,總是讓人吃驚。也有點小驚喜。

有不懂的可以直接回復筆者,筆者不定期回覆。歡迎各位俠義之士共同進步。