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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

jni直接转byte_JNI再探之JNI 数据类型及Java与C++之间互调

發布時間:2025/3/20 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jni直接转byte_JNI再探之JNI 数据类型及Java与C++之间互调 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JNI

什么是JNI

JNI,全稱Java NativeInterface,是一種為Java編寫本地方法和JVM嵌入本地應用程序標準的應用程序接口,它允許運行在JVM上的Java代碼能夠與C/C++實現的本地庫進行交互。

JNI 數據類型

Java中有兩種類型:基本數據類型(int、float、char等)和引用類型(類、對象、數組等)。 JNI定義了一個C/C++類型的集合,集合中每一個類型對應于Java中的每一個類型,其中,對于基本類型而言,JNI與Java之間的映射是一對一的,比如Java中的int類型直接對應于C/C++中的jint;而對引用類型的處理卻是不同的,JNI把Java中的對象當作一個C指針傳遞到本地函數中,這個指針指向JVM中的內部數據結構,而內部數據結構在內存中的存儲方式是不可見的,本地代碼必須通過在JNIEnv中選擇適當的JNI函數來操作JVM中的對象。比如,對于java.lang.String對應的JNI類型是jstring,但本地代碼只能通過GetStringUTFChars這樣的JNI函數來訪問字符串的內容。

JNI映射表

| Java 類型 | JNI本地類型 |方法簽名 | 描述 | | ------ |------|------|------| | boolean | jboolean | Z | unsigned 8 bits| | byte | jbyte | B |signed 8 bits| | char | jchar | C |unsigned 16 bits| | short | jshort | S | signed 16 bits | | int | jint | I | signed 32 bits | | long | jlong | J | signed 64 bits | | float | jfloat | F | 32bits | | double | jdouble | D | 64bits | | void | Void | V | - |

方法簽名

由于Java支持方法重載,在JNI訪問Java層方法時僅靠函數名是無法唯一確定一個方法,因此JNI提供了一套簽名規則(如:Z、B、[Z等),用一個字符串來唯一確定一個方法,其規則:(參數1類型簽名參數2類型簽名…)返回值類型簽名,比如Java方法long getDeviceId(int n, String s, int[] arr)、long getDeviceId(int n)的類型簽名分別為(ILjava/lang/String;[I)J、(I)J。 1. 基本類型: boolean ->Z,byte-> B,char -> C,short-> S,int->I,long->J,float-> F,double->D,void -> V; 2. 如果是類的類型:L+類全名,類名中的.用/代替,比如java.lang.String就是Ljava/lang/String; 3. 如果是數組類型:則在前面加上 然后加類型簽名,幾位數組就加幾個,比如int[]->[I,boolean[][]->[[Z,java.lang.Class[] -> [Ljava/lang/Class; 可以通過javap -s來打印該方法的簽名

Example: public static native String getName(); public static native int calculate(int a,int b);

通過Rebuild Project才會在app中的intermediates目錄下javac/debug生成class文件,找到 類到地址 然后右鍵打開命令行

在命令行輸入 javap -s JNIUtils.class 即可獲取到2個方法到簽名,我這里是JNIUtils獲取的兩個簽名如下:

警告: 二進制文件JNIUtils包含com.example.nativejnidemo.JNIUtils Compiled from "JNIUtils.java" public class com.example.nativejnidemo.JNIUtils {public com.example.nativejnidemo.JNIUtils();descriptor: ()Vpublic static native java.lang.String getName(); //括號為空表示當前沒有參數descriptor: ()Ljava/lang/String; //括號中有兩個參數則表示為該類型的簽名I I在返回該方法簽名類型Ipublic static native int calculate(int, int);descriptor: (II)I

Android studio 3.0 打印日志

  • 首先在app下的build.gradle中添加ldLibs("log")
// 指定ABI ndk {ldLibs("log")abiFilters 'x86', 'x86_64', 'armeabi-v7a','arm64-v8a' }

然后在cpp文件中添加

#include <android/log.h> #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "========= Info ========= ", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "========= Error ========= ", __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_INFO, "========= Debug ========= ", __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "========= Warn ========= ", __VA_ARGS__) 最后調用 `LOGI("from c log");`
  • 還有一種通過Cmake構建的ndk工程, 導入log庫 在build.gradle中加入ldLibs "log":
android {defaultConfig {ndk{ldLibs "log"}} }

JNI 函數解析

Java調用C/C++ 本地函數

/*** CPP 源文件,返回一個字符串* @param env* @return*/ Java_com_example_jnilearndemo_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str()); } /*** C 源文件,返回一個字符串* @param env* @return*/ Java_com_example_jnilearndemo_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";return (*env)->NewStringUTF(env,hello.c_str()); }

當源文件為.cpp時,只需要傳env ->就可以;而當源文件為.c時,就需要傳入(*env)->。
上面兩個函數作用都是當Java層調用本地方法時向Java層返回一個UTF-8格式的字符串。兩個函數使用方法不同原因:主要是因為這兩個函數是在不同的源文件中實現的。通過查看jni.h源碼可知,當源文件為.cpp時,JNIEnv實際為結構體JNIEnv_,然后我們再查看JNIEnv_結構體的內容,找到NewStringUTF(constchar *utf)函數,它實際執行了functions->NewStringUTF(this,utf)函數,而這個函數默認傳遞了一個this參數,該this參數則指的是getStringFromC函數原型中JNIEnv指針變量參數。因此,使用C++開發JNI時就無需再傳遞JNIEnv指針變量且在使用JNIEnv_結構體的成員時,直接使用結構體變量指向成員即可。

#ifdef__cplusplus // 如果為C++,JNIEnv表示JNIEnv_ typedef JNIEnv_ JNIEnv; #else // 如果不為C++,JNIEnv表示JNINativeInterface_* typedef const struct JNINativeInterface_ * JNIEnv; #endif structJNIEnv_ {const struct JNINativeInterface_*functions; #ifdef__cplusplus …… jstringNewStringUTF(const char *utf) {returnfunctions->NewStringUTF(this,utf); } …… #endif

當源文件為.c時,JNIEnv實際表示的JNINativeInterface_*,JNIEnv*env即JNINativeInterface_**env,因此,我們在調用JNINativeInterface_結構體中的成員時需要使用一級指針來實現,即(*env)->成員。然后,再繼續查看JNINativeInterface_源碼,NewStringUTF函數需要傳入一個JNIEnv結構體類型指針變量,該指針變量指向JNINativeInterface_結構體存儲的地址,因此,還需要將變量env賦值給NewStringUTF即可。

structJNINativeInterface_ {jstring (JNICALL *NewStringUTF) (JNIEnv*env, const char *utf); }

C/C++ 訪問Java層屬性及方法

C/C++層訪問Java層對象的實例變量與實例方法

首先獲取構造方法,再通過構造方法獲取類對象,根據類對象調用實例方法;構造方法通過進行標識,傳遞參數為空,返回值也為空。

//C++調用java的實例方法與實例變量 extern "C" JNIEXPORT void JNICALL Java_com_example_jnilearndemo_JNIUtils_callInstanceMethod(JNIEnv *env, jobject instance, jint i) {jclass cls_jniutils = env->FindClass("com/example/jnilearndemo/JNIUtils");if(cls_jniutils==NULL){return;}jmethodID method_instance = env->GetMethodID(cls_jniutils,"method","(Ljava/lang/String;)V");if(method_instance==NULL){return;}//首先獲取構造方法,再通過構造方法獲取類對象,根據類對象調用實例方法;構造方法通過<init>進行標識,傳遞參數為空,返回值也為空jmethodID method_construct = env->GetMethodID(cls_jniutils,"<init>","()V");if(method_construct==NULL){return;}//創建相應的對象,最后參數為空,不需要傳遞參數jobject jnutils = env->NewObject(cls_jniutils,method_construct,NULL);if(jnutils==NULL){return;}jstring msg = env->NewStringUTF("call instance method");//調用Java中的實例變量jfieldID filed_instance = env->GetFieldID(cls_jniutils,"address","Ljava/lang/String;");if(filed_instance==NULL){return;}jstring address = env->NewStringUTF("suzhou");//設置實例變量,需要傳遞對象env -> SetObjectField(jnutils,filed_instance,address);env -> CallVoidMethod(jnutils,method_instance,msg);env->DeleteLocalRef(msg);env->DeleteLocalRef(cls_jniutils);env->DeleteLocalRef(jnutils);env->DeleteLocalRef(address); } public class JNIUtils {static {//加載動態庫System.loadLibrary("JNILearning");}public static String name = "ztz";public String address = "hangzhou";public static native int calculate(int a,int b);public static native void callInstance(int i);public native void callInstanceMethod(int i);public static void LogMessage(String msg){Log.i("C++調用java中的static方法", "LogMessage: "+msg);}public static void staticMethod(String msg){LogMessage(msg);LogMessage(name);}public void method(String msg){LogMessage(msg);LogMessage(address);} }

C/C++層訪問Java類的靜態屬性

在.cpp格式的源碼文件中: Java 代碼

public class JNIUtils {static {//加載動態庫System.loadLibrary("JNILearning");}public static String name = "ztz";public static native int calculate(int a,int b);public static native void callInstance(int i);public static void LogMessage(String msg){Log.i("C++調用java中的static方法", "LogMessage: "+msg);}public static void staticMethod(String msg){LogMessage(msg);LogMessage(name);} }

JNI C++層代碼

extern "C" JNIEXPORT void JNICALL Java_com_example_jnilearndemo_JNIUtils_callInstance(JNIEnv *env, jclass type, jint i) {// TODO 當源文件為.cpp時,只需要傳env ->就可以;而當源文件為.c時,就需要傳入(*env)->//查找類jclass cls_jniutils = env -> FindClass("com/example/jnilearndemo/JNIUtils");//判斷是否找到,沒找到返回if(cls_jniutils==NULL){return;}//修改java中的靜態變量jfieldID field_name = env->GetStaticFieldID(cls_jniutils,"name","Ljava/lang/String;"); //這里要進行空安全檢查,JNI與Java處理異常機制不一樣,Java遇到異常如果沒有捕獲,程序就立即停止運行,而JNI遇到異常,程序會繼續執行下去, 這樣針對后面的操作非常危險,所以要return跳過后面代碼執行。if(field_name==NULL){return;}jstring new_name = env->NewStringUTF("yif"); //對成員變量進行重新設置env->SetStaticObjectField(cls_jniutils,field_name, new_name);//調用之前methodId所對應的的靜態方法env ->CallStaticVoidMethod(cls_jniutils,method_static,data);//最后釋放之前創建的對象,這里為局部引用env ->DeleteLocalRef(cls_jniutils);env->DeleteLocalRef(new_name); }

NewStringUTF函數: 通過調用NewStringUTF函數,會構建一個新的java.lang.String字符串對象。這個新創建的字符串會自動轉換成Java支持的Unicode編碼。如果JVM不能為構造java.lang.String分配足夠的內存,NewStringUTF會拋出一個OutOfMemoryError異常,并返回NULL。在這個例子中我們不必檢查它的返回值,如果NewStringUTF創建java.lang.String失敗,OutOfMemoryError這個異常會被在調用JNI層方法的Java類方法中拋出,比如這里的JNIUtils類。如果NewStringUTF創建java.lang.String成功,則返回一個JNI引用,這個引用指向新創建的java.lang.String對象。

C/C++層訪問Java類的靜態方法

  • 在.c格式的源文件中的操作: Java代碼
  • public class JNIUtils {static {System.loadLibrary("HelloJNI");}public static void LogMessage(String msg){Log.i("C++調用java中的static方法", "LogMessage: "+msg);}public static void staticMethod(String msg){LogMessage(msg);}public static native void callInstance(int i); }

    C++層代碼

    JNIEXPORT void JNICALL Java_com_example_nativejnidemo_JNIUtils_callInstance__I(JNIEnv *env, jclass type, jint i) {// TODO 當源文件為.cpp時,只需要傳env ->就可以;而當源文件為.c時,就需要傳入(*env)->//查找類jclass cls_hello = (*env)->FindClass(env,"com/example/jnilearndemo/JNIUtils");//判斷是否找到,沒找到返回if(cls_hello==NULL){return;}//然后在查找該類下的方法,參數env,查找的類,查找的方法,方法對應的簽名jmethodID method_static = (*env)->GetStaticMethodID(env,cls_hello,"staticMethod","(Ljava/lang/String;)V");if(method_static==NULL){return;}//傳遞參數為String,所以要創建String對象jstring data = (*env) -> NewStringUTF(env,"call static method");if(data==NULL){return;}//調用之前methodId所對應的的靜態方法(*env) ->CallStaticVoidMethod(env,cls_hello,method_static,data);//最后釋放之前創建的對象,這里為局部引用(*env)->DeleteLocalRef(env,cls_hello);(*env)->DeleteLocalRef(env,data); }
  • 在.cpp格式的源文件中的操作:
  • extern "C" JNIEXPORT void JNICALL Java_com_example_jnilearndemo_JNIUtils_callInstance(JNIEnv *env, jclass type, jint i) {// TODO 當源文件為.cpp時,只需要傳env ->就可以;而當源文件為.c時,就需要傳入(*env)->//查找類jclass cls_jniutils = env -> FindClass("com/example/jnilearndemo/JNIUtils");//判斷是否找到,沒找到返回if(cls_jniutils==NULL){return;}//然后在查找該類下的方法,參數查找的類,查找的方法,方法對應的簽名jmethodID method_static = env ->GetStaticMethodID(cls_jniutils,"staticMethod","(Ljava/lang/String;)V");if(method_static==NULL){return;}//傳遞參數為String,所以要創建String對象jstring data = env->NewStringUTF("call static method");if(data==NULL){return;}//調用之前methodId所對應的的靜態方法env ->CallStaticVoidMethod(cls_jniutils,method_static,data);//最后釋放之前創建的對象,這里為局部引用env ->DeleteLocalRef(cls_jniutils);env->DeleteLocalRef(data); }

    總結

    以上是生活随笔為你收集整理的jni直接转byte_JNI再探之JNI 数据类型及Java与C++之间互调的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日韩av一区在线播放 | 国产成人精品一区二区三区视频 | 尤物精品视频 | 嫩草影院av| 中文字幕女同女同女同 | 九色91在线 | 欧美日韩视频 | 四虎影视8848hh | 国模在线观看 | 激情小说激情视频 | 偷自在线| 伊人久久97 | 欧美日韩极品 | 99热在线国产 | 成人黄色在线观看 | 在线国产毛片 | 成人四色 | 最好看十大无码av | 天天干,天天操,天天射 | 黄瓜视频91| 精品成人无码一区二区三区 | 成人在线观看免费网站 | 农村激情伦hxvideos | 欧美日韩视频一区二区三区 | 德国性猛交xxxxhd | 久久精品视频一区二区 | 最好看的中文字幕国语电影mv | 国产做爰xxxⅹ高潮视频12p | 国产第一区第二区 | 婷婷综合国产 | 精品三级在线观看 | 精品国产乱码久久久久久图片 | 久久国产视频网站 | 国产精品视频看看 | 97超在线 | 久久精品国产精品亚洲 | 欧美人与zoxxxx另类 | 免费欧美| 1769国产精品视频 | 日韩在线观看一区 | 天堂av片 | 五月色综合 | 伊人网亚洲 | 久久久无码精品亚洲国产 | 久久6精品 | 无码免费一区二区三区免费播放 | 久久久久网站 | 污污视频免费网站 | 日韩精品v | 91刺激视频| 精品国产露脸精彩对白 | 久久人人爽天天玩人人妻精品 | 午夜成人在线视频 | 69视频网址 | 成人毛片软件 | 九九久久精品 | 久久精工是国产品牌吗 | 久久无码性爱视频 | 黄视频免费看在线 | 捆绑无遮挡打光屁股 | 午夜三级视频 | 国产精品传媒在线观看 | 麻豆视频免费看 | 国产成人免费在线视频 | 熟妇人妻av无码一区二区三区 | 国产欧美精品在线 | 亚洲av日韩av高潮潮喷无码 | 夜色伊人| 国产成人精品一区二区在线小狼 | 99久久婷婷国产综合精品草原 | 免费在线毛片 | 国产乱淫av麻豆国产免费 | 伊人久久久久久久久久久久久 | 久久久国产精品无码 | 国产精品麻豆欧美日韩ww | 国产精品视频一区二区三区不卡 | 欧美三级一区 | 色在线免费观看 | 欧美又粗又深又猛又爽啪啪九色 | www.久色| 锕锕锕锕锕锕锕锕 | 午夜福利电影一区 | 玖玖精品| 草草在线视频 | 成人性生交大片 | 日韩精品三区 | 免费无码不卡视频在线观看 | 成人午夜免费网站 | 精品区一区二区 | 精品三级电影 | 日本一级视频 | 欧洲精品久久久 | 国产专区av| 成人 黄 色 免费播放 | 国产欧美三级 | 亚洲成a人 | av一区二区三区在线 | 精品国产a线一区二区三区东京热 | 精品自拍一区 |