歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

JNI通過動態注冊實現native函數

一、概述
通過javah工具將java代碼中的native聲明的函數生成標准的C/C++函數頭,每個函數的名字都很長(Java_包名_類名_函數名),這樣C/C++函數的函數名就是定死的,不能修改,否則java找不到函數。這裡還有種方式,通過注冊的方式將C/C++的函數與java中的native函數進行一一對應的,函數名可以任意書寫。

二、代碼實現
SimpleJni.java

package com.bt.jni;
 
public class SimpleJni {
 
 static {
  System.out.println("[java]static code block, start load shared library....");
  System.loadLibrary("simpleJni");
  System.out.println("[java]load library end....");
 }
 
 static native int add(int a, int b);
 
 public static void main(String args[]) {
  System.out.println("[java] in main()...");
  System.out.println("[java] 3 + 5 = " + SimpleJni.add(3, 5));
  System.out.println("[java] main() end...");
 }
 
}

simple_jni.c
#include "jni.h"
#include <stdio.h>
 
 
const char *classPathName = "com/bt/jni/SimpleJni";
 
/**
 native 函數的實現
**/
jint myadd(JNIEnv *env, jobject thiz, jint a, jint b)
{
 return a + b;
}
 
static JNINativeMethod methods[] = {
 //{native函數名,函數簽名, C中函數實現名}
 {"add", "(II)I", (void*)myadd},
};
 
int registerNatives(JNIEnv *env)
{
 jclass clazz;
 
 //根據類的全路徑,獲得類的字節碼信息
 clazz = (*env)->FindClass(env, classPathName);
 if (NULL == clazz) {
  printf("[C] FindClass() failed...\n");
  goto failed;
 }
 
 //將c函數與字節碼中的native函數進行映射
 if (0 > (*env)->RegisterNatives(env, clazz, methods, sizeof(methods)/sizeof(methods[0]))) {
  printf("[C] RegisterNatives() failed...\n");
  goto failed;
 }
 
 return JNI_TRUE;
 
failed:
 return JNI_FALSE;
}
 
/**
 java 在加載動態庫的時候,自動調用此函數,注冊native函數
**/
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
 JNIEnv *env = NULL;
 jint result = -1;
 void **env_p = NULL;
 
 printf("[C] start register native func...\n");
 
 env_p = (void**)&env;
 
 //首先從java虛擬機中獲得env
 if (JNI_OK != (*vm)->GetEnv(vm, env_p, 0x00010004)) {
  printf("[C] GetEnv() failed...will exit\n");
  goto err;
 }
 
 //通過env進行函數的注冊
 if (JNI_TRUE != registerNatives(env)) {
  printf("[C] register func failed...will exit\n");
  goto err;
 }
 
 result = 0x00010004;
 printf("[C] register end...\n");
err:
 return result;
}

操作步驟
    1.首先編寫SimpleJni.java和simpel_jni.c
    2.編譯java和c文件
$ java -d .  SimpleJni.java
$gcc -fPIC -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/ -o libsimpleJni.so simple_jni.c

    3.執行
    $java -Djava.library.path=. com.bt.jni.SimpleJni

    結果:
    [java]static code block, start load shared library....
    [C] start register native func...
    [C] register end...
    [java]load library end....
    [java] in main()...
    [java] 3 + 5 = 8
    [java] main() end...

根據結果可知,java首先執行靜態代碼塊,其中在加載動態庫的時候,自動調用JNI_OnLoad函數,建立native函數和c中的函數映射關系,最後進入main函數。

Copyright © Linux教程網 All Rights Reserved