日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA进阶day07JNI(java调用c)A部分

發(fā)布時(shí)間:2023/12/9 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA进阶day07JNI(java调用c)A部分 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目前接觸的JNI有java調(diào)用c和c調(diào)用java兩類。其中java調(diào)用c又有隱式和顯示兩種映射關(guān)系。本筆記針對java調(diào)用c的顯示映射。本著工程實(shí)際夠用的原則,不夠再回頭來補(bǔ)充。
JAVA訪問c庫需要有三個(gè)步驟
1:加載C庫
2:建立java函數(shù)名到c庫函數(shù)名的映射關(guān)系
3:在java程序里調(diào)用函數(shù)
先貼代碼,依照代碼來做分析:

public class JNIDemo {static { /* 1. load */System.loadLibrary("native"); /* libnative.so */}public native void hello();public static void main (String args[]) {JNIDemo d = new JNIDemo(); /* 2. map java hello <-->c c_hello *//* 3. call */d.hello();} }

分條縷析做筆記:

  • 1:加載C庫和在java程序里調(diào)用函數(shù)
static { /* 1. load */System.loadLibrary("native"); /* libnative.so */}

代碼中在靜態(tài)代碼塊中進(jìn)行加載c庫。可以知道我們要加載的是libnative.so庫。放到靜態(tài)代碼塊中可以保證該加載能夠只執(zhí)行一次。非常棒的處理。

public native void hello();

native修飾的hello表明這個(gè)hello方法不是在java中實(shí)現(xiàn)的而是在本地語言中實(shí)現(xiàn)的。我們在使用hello函數(shù)的時(shí)候首先要進(jìn)行聲明。這個(gè)聲明也可以聲明為靜態(tài)的,比如public native static void hello();這時(shí)候就沒有必要先實(shí)現(xiàn)JNIDemo的實(shí)例化靜態(tài)對象了,也就是說我們可以省掉JNIDemo d=new JNI Demo();這個(gè)處理,直接使用JNIDemo.hello();當(dāng)然我們的main函數(shù)也是在JNIDemo類中的,可以直接寫為hello()。問題又來了,那么同樣的道理為什么不是靜態(tài)的還需要實(shí)現(xiàn)JNIDemo對象呢,這個(gè)也是在JNIDemo的main函數(shù)中啊?這個(gè)就沒必要較真了,記住就好,又不是讓你去創(chuàng)造java語言,你只不過是用這個(gè)工具而已。我還發(fā)現(xiàn)這個(gè)public native static void hello()跟public static native void hello()是一個(gè)效果。無礙乎這個(gè)static跟native的前后。到此我們對這個(gè)加載c庫就算是掌握了。

  • 2:建立java函數(shù)名到c庫函數(shù)名的映射關(guān)系
    為了將java中的hello跟c語言中的函數(shù)對應(yīng)起來,這部分的處理是c語言中做的。我們姑且猜測,c語言在什么時(shí)候去做這個(gè)映射對應(yīng)呢?我提出一個(gè)想法,我們在加載SystemloadLibrary的時(shí)候會引起c庫文件中的一個(gè)觸發(fā),在那個(gè)觸發(fā)函數(shù)里面做了對應(yīng)。那么我們從文件中的結(jié)構(gòu)應(yīng)該是包含 觸發(fā) 實(shí)現(xiàn)。我們貼代碼分析:
#include <jni.h> /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */ #include <stdio.h>#if 0 typedef struct {char *name; /* Java里調(diào)用的函數(shù)名 */char *signature; /* JNI字段描述符, 用來表示Java里調(diào)用的函數(shù)的參數(shù)和返回值類型 */void *fnPtr; /* C語言實(shí)現(xiàn)的本地函數(shù) */ } JNINativeMethod; #endifvoid c_hello(JNIEnv *env, jobject cls) {printf("Hello, world!\n"); }static const JNINativeMethod methods[] = {{"hello", "()V", (void *)c_hello}, };/* System.loadLibrary */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {JNIEnv *env;jclass cls;if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {return JNI_ERR; /* JNI version not supported */}cls = (*env)->FindClass(env, "JNIDemo");if (cls == NULL) {return JNI_ERR;}/* 2. map java hello <-->c c_hello */if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)return JNI_ERR;return JNI_VERSION_1_4; }

我們看到,果不其然跟我們猜測的一模一樣。
的確是分為兩部分。最頂層那部分實(shí)現(xiàn)了c_hello函數(shù),最下半部分實(shí)現(xiàn)了一個(gè)JNI_OnLoad觸發(fā)函數(shù)。哇咔咔,一切都這么順滑。那我們開墾這個(gè)觸發(fā)函數(shù)吧。
該函數(shù)功能比較單一所以寫法肯定是固定的。每次使用我們只需要去修改這么幾個(gè)點(diǎn)就可以了:
JNI_VERSION_1_4 這個(gè)代表的是你使用的jni的版本。

cls = (*env)->FindClass(env, "JNIDemo");

這個(gè)作用就是從env找到JNIDemo這個(gè)類,方面后面我們?nèi)プ鲇成洹9识@個(gè)JNIDemo我們做移植的時(shí)候是需要去修改的。

if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)

這個(gè)地方也就是我們想要的注冊了。后面的1代表你要注冊的個(gè)數(shù)。
我們再看看這個(gè)注冊methods里面的實(shí)現(xiàn)。

static const JNINativeMethod methods[] = {{"hello", "()V", (void *)c_hello}, };

這個(gè)模式也是固定的
其中“hello”對應(yīng)的是java中的函數(shù)名字。c_hello對應(yīng)的c文件中的函數(shù)名字。前面的void * 是永遠(yuǎn)不變的。中間的這個(gè)類型signature我是打死也不想記住怎么寫的。我們可以在寫完java文件之后使用javac JNIDemo.java進(jìn)行編譯然后使用
javah -jni JNIDemo
生成一個(gè)JNIDemo.h文件

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

我們從里面摘取

/** Class: JNIDemo* Method: hello* Signature: ()V*/

就知道這個(gè)signature 就是()V.
同時(shí)我們知道我們的c文件的hello函數(shù)書寫形式應(yīng)該類似與

JNIEXPORT void JNICALL Java_JNIDemo_hello(JNIEnv *, jclass);

實(shí)際中我們的c語言函數(shù)書寫是

void c_hello(JNIEnv *env, jobject cls)

幾乎是一樣的,其中jobject 跟jclass我覺得應(yīng)該是java編譯器不同導(dǎo)致的,我感性的認(rèn)為應(yīng)該是兼容的,都能用。既然我的編譯器出來的是jclass那么我的代碼就修改為

void c_hello(JNIEnv *env, jclass cls)

寫到這里,還剩下兩件事,怎樣編譯c文件為lib*.so以及java同c語言文件如何傳遞返回?cái)?shù)據(jù)類型。我們知道java跟c的數(shù)據(jù)類型上是有區(qū)別的。包括開辟的空間大小等。最起碼的java中有string類型,然而我們的c語言中就沒有。因此,這部分還算是一個(gè)不大不小的知識點(diǎn)。按下不表下集再說。

總結(jié)

以上是生活随笔為你收集整理的JAVA进阶day07JNI(java调用c)A部分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。