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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

实现一个在JNI中调用Java对象的工具类,从此只需一行代码

發(fā)布時(shí)間:2024/4/15 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实现一个在JNI中调用Java对象的工具类,从此只需一行代码 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

我們知道在jni中執(zhí)行一個(gè)java函數(shù)需要調(diào)用幾行代碼才行,如

jclass objClass = (*env).GetObjectClass(obj); jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig); jobject result = (*env).CallObjectMethod(obj, methodID, ...);

這樣使用起來(lái)很不方便,尤其當(dāng)需要大量的調(diào)用java函數(shù)就會(huì)產(chǎn)生大量的上述代碼,由此我產(chǎn)生了一個(gè)開(kāi)發(fā)封裝這些操作的工具類(lèi),以便大量簡(jiǎn)化我們的開(kāi)發(fā)。

簡(jiǎn)單封裝

其實(shí)可以看到整個(gè)過(guò)程基本是固定不變的:先獲取Class,然后獲取method,然后在執(zhí)行call。所以可以簡(jiǎn)單的先封裝成一系列工具函數(shù),如:

jobject callObjMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);jobject result = (*env).CallObjectMethodV(obj, methodID, args);va_end(args);return result; }jint callIntMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);jint result = (*env).CallIntMethodV(obj, methodID, args);va_end(args);return result; }jboolean callBooleanMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);jboolean result = (*env).CallBooleanMethodV(obj, methodID, args);va_end(args);return result; }

這樣當(dāng)我們要通過(guò)jni執(zhí)行某個(gè)java函數(shù)的時(shí)候,就一行代碼就可以搞定了,比如String.length():

jint len = callIntMethod(env, str, "length", "()I")

這樣就可以大大減少了代碼量,而且代碼也更易讀了。

優(yōu)化

通過(guò)上面可以看到這些函數(shù)大部分代碼都非常類(lèi)似,只有一行代碼和返回值有區(qū)別,所以我考慮使用函數(shù)模版來(lái)進(jìn)行優(yōu)化,如下:

template <typename T> T callMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);T result;if(typeid(T) == typeid(jobject)){result = (*env).CallObjectMethodV(obj, methodID, args);}if(typeid(T) == typeid(jdouble)){result = (*env).CallDoubleMethodV(obj, methodID, args);}...va_end(args);return *result; }

這樣只要調(diào)用callMethod<return type>即可,愿望很美好,但是上面代碼實(shí)際上是無(wú)法通過(guò)編譯。

因?yàn)槟0婧瘮?shù)實(shí)際上是在編譯時(shí),根據(jù)調(diào)用的類(lèi)型,拷貝生成多個(gè)具體類(lèi)型的函數(shù)以便使用。

所以如果有這樣的調(diào)用callMethod<jobject>(...),在編譯時(shí)就會(huì)拷貝成一個(gè)如下的函數(shù):

jobject callMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);jobject result;if(typeid(jobject) == typeid(jobject)){result = (*env).CallObjectMethodV(obj, methodID, args);}if(typeid(jobject) == typeid(jdouble)){result = (*env).CallDoubleMethodV(obj, methodID, args);}...va_end(args);return *result; }

注意這行代碼:

if(typeid(jobject) == typeid(jdouble)){result = (*env).CallDoubleMethodV(obj, methodID, args); }

雖然實(shí)際上是無(wú)法執(zhí)行的代碼,但是編譯時(shí)還是會(huì)進(jìn)行檢查,由于將jdouble類(lèi)型的賦值給jobject類(lèi)型的result,所以編譯不通過(guò),類(lèi)型無(wú)法轉(zhuǎn)換。而且這里用強(qiáng)轉(zhuǎn)static_cast等方法都不行。

我考慮兩種方法來(lái)解決這個(gè)問(wèn)題,一種是保證編譯不報(bào)錯(cuò),因?yàn)檫\(yùn)行時(shí)不會(huì)執(zhí)行的代碼,只要通過(guò)編譯就可以。另外一種是不同的類(lèi)型編譯不同的代碼。

void指針

在c++中void指針可以被賦值任何類(lèi)型指針,且void指針強(qiáng)轉(zhuǎn)為任何類(lèi)型指針在編譯時(shí)不會(huì)報(bào)錯(cuò)。代碼如下:

template <typename T> T callMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);T* result = new T();if(typeid(T) == typeid(jobject)){jobject objec = (*env).CallObjectMethodV(obj, methodID, args);void *p = &objec;result = (T*)p;}if(typeid(T) == typeid(jdouble)){jdouble doub = (*env).CallDoubleMethodV(obj, methodID, args);void *p = &doub;result = (T*)p;}va_end(args);return *result; }

當(dāng)然利用void指針很不安全,雖然可以通過(guò)編譯,但是執(zhí)行時(shí)如果類(lèi)型不同會(huì)直接造成crash。所以并不建議這種方式。

模版函數(shù)特例化

將差異代碼部分封裝到另一個(gè)模版函數(shù)中,并且對(duì)每種類(lèi)型進(jìn)行特例化,這樣還可以去掉if-else判斷,代碼如下:

template <typename K> K call2Result(JNIEnv *env, jobject obj, jmethodID methodID, va_list args){return *(new K()); }template <> jobject call2Result(JNIEnv *env, jobject obj, jmethodID methodID, va_list args){return (*env).CallObjectMethodV(obj, methodID, args); }template <> jdouble call2Result(JNIEnv *env, jobject obj, jmethodID methodID, va_list args){return (*env).CallDoubleMethodV(obj, methodID, args); } ...template <typename T> T callMethod(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, ...){va_list args;jclass objClass = (*env).GetObjectClass(obj);jmethodID methodID = (*env).GetMethodID(objClass, methodName, methodSig);va_start(args,methodSig);T result = call2Result<T>(env, obj, methodID, args);va_end(args);return result; }

這樣在編譯時(shí),如果返回值是jobject類(lèi)型的,當(dāng)編譯到call2Result時(shí),就會(huì)直接調(diào)用jobject call2Result(...)這個(gè)函數(shù),就不再涉及類(lèi)型轉(zhuǎn)換的問(wèn)題。

這樣去掉了if判斷,但是由于沒(méi)有通用的函數(shù),所以所有使用的類(lèi)型都需要特例化,如果某個(gè)類(lèi)型未特例化,代碼執(zhí)行可能就會(huì)有問(wèn)題。而在jni中,與java對(duì)應(yīng)的類(lèi)型其實(shí)就那么十幾種,所以我們只要全部實(shí)現(xiàn)一遍call2Result即可。

undefined reference to

使用模版函數(shù)出現(xiàn)這個(gè)問(wèn)題,是因?yàn)闆](méi)有將模版函數(shù)的實(shí)現(xiàn)寫(xiě)在頭文件中,只將模版函數(shù)的聲明在頭文件中,而在源文件中實(shí)現(xiàn)的。

所以我們應(yīng)該將模版函數(shù)的實(shí)現(xiàn)也寫(xiě)進(jìn)頭文件中,而模版函數(shù)特例化則可以在源文件中實(shí)現(xiàn),但是注意要include頭文件。

返回值是void類(lèi)型

因?yàn)関oid的特殊性,所以如果當(dāng)成泛型來(lái)處理會(huì)有很多問(wèn)題,這里把返回值是void類(lèi)型的單獨(dú)實(shí)現(xiàn)一個(gè)函數(shù)即可。

總結(jié)

上面我們僅僅是實(shí)現(xiàn)了調(diào)用普通函數(shù)的工具,根據(jù)這個(gè)思路我們還可以實(shí)現(xiàn)調(diào)用靜態(tài)函數(shù)、獲取成員變量、賦值成員變量等,這樣當(dāng)我們?cè)谶M(jìn)行jni開(kāi)發(fā)的時(shí)候,如果需要對(duì)java對(duì)象或類(lèi)進(jìn)行操作,只需要一行代碼就可以了。

源碼

關(guān)注公眾號(hào):BennuCTech,發(fā)送“JNIObjectTools”獲取源碼。

總結(jié)

以上是生活随笔為你收集整理的实现一个在JNI中调用Java对象的工具类,从此只需一行代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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

主站蜘蛛池模板: 国产第1页| 91春色| 人人干人人舔 | 国产夫妻性生活视频 | 蜜桃久久久久久久 | 亚洲天天操 | 国产私人影院 | 少妇太紧太爽又黄又硬又爽小说 | 国产99久久久国产精品免费看 | 人妻体内射精一区二区三区 | 久久精品首页 | 好男人香蕉影院 | 欧美激情一区二区三区 | 日韩播放 | 亚洲少妇18p | 日韩视频免费在线播放 | 福利国产在线 | 欧美一级啪啪 | 国产在线视频福利 | 在线91视频 | 亚洲福利社 | 中文字幕一区二区精品 | 原来神马电影免费高清完整版动漫 | 日韩一区久久 | 国产看黄网站 | 成人免费网站在线观看 | 精品久久人人妻人人做人人 | 亚洲成av人片 | 浓精喷进老师黑色丝袜在线观看 | 国产成人精品999在线观看 | 老湿机69福利区午夜x片 | 91av在线视频播放 | 亚洲福利一区二区三区 | 国产乱论 | 原来神马电影免费高清完整版动漫 | 91高清国产 | 一级α片免费看刺激高潮视频 | 毛片免费全部无码播放 | 欧美成人一区二区三区片免费 | 日噜噜夜噜噜 | 欧美日韩国产高清 | 91av色| 午夜精品一二三区 | 国产精品一区三区 | 久啪视频 | 少妇爽 | 欧美另类视频在线 | 亚洲图片欧美色图 | 中日韩精品视频 | 久草综合网 | 精品色综合 | 伊人久久大香 | 国产精品自拍网站 | 麻豆精品视频免费观看 | 天堂网视频在线 | 91看片免费看 | 久久丫精品 | 日本久久一级片 | 天堂…中文在线最新版在线 | 国产盗摄精品一区二区酒店 | 国产精品福利一区二区三区 | 欧美性受xxxx黒人xyx性爽 | 中文字幕一区二区人妻痴汉电车 | 国产激情a | 免费 成 人 黄 色 | 毛片视频在线免费观看 | 中文字幕在线视频一区 | 欧美亚洲国产一区 | 欧美精品91| 国产欧美熟妇另类久久久 | 九七电影院97理论片 | 深夜视频在线免费观看 | 日本精品一区二区三区在线观看 | 黄网在线免费 | 一区二区啪啪啪 | 免费成人在线播放 | 黑人与日本少妇 | 清纯唯美亚洲激情 | 亚洲AV午夜精品 | 日韩精品电影一区二区 | 欧美在线播放视频 | 国产懂色av | 日本妈妈3 | 超在线视频 | 久久免费视频2 | 日本xxxxxxxxx18| 性欧美又大又长又硬 | 国产欧美精品一区二区色综合 | 99色精品 | 操夜夜 | 国产精品伦一区二区 | 国产日韩一区二区三区 | 免费小视频 | 国产精品海角社区 | 天天做夜夜爱 | 在线观看中文字幕2021 | 亚洲三级小视频 | 欧美性生话 | 国产成人在线播放视频 |