一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Java層調(diào)用native層的方法

 思想戰(zhàn)神 2020-05-07

前言

http://www./archives/1097中,我介紹了下了如何編寫一個簡單的Demo來讓native輸出hello world到j(luò)ava層,接下來本篇主要介紹Java層調(diào)用native方法,以及native層調(diào)用Java層的方法以及修改Java對象的屬性。

Java層調(diào)用native層的方法

其實(shí)在上一篇中已經(jīng)介紹了下如何調(diào)用native層方法,其實(shí)與調(diào)用普通的Java方法沒有什么區(qū)別,只是方法由native層實(shí)現(xiàn)的而已。

首先我們在Java類中編寫native方法,然后使用上一篇博客中介紹的方法在native層實(shí)現(xiàn)之。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.ndk.ndkfirst;
public class NDKTest {
    private static final String TAG = "NDKTest";
    static {
        System.loadLibrary("ndk-test-lib");
    }
    private String mString = "Ndk test string";
    /**
     * 在native中進(jìn)行加法運(yùn)算
     */
    public native int calcInNative(int num1, int num2);
}
1
2
3
4
5
6
7
8
9
#include <jni.h>
extern "C"
{
JNIEXPORT jint JNICALL
Java_org_ndk_ndkfirst_NDKTest_calcInNative(JNIEnv *env, jobject obj, jint num1, jint num2) {
return num1 + num2;
}
}

我們可以看到,只是將加法運(yùn)算在native層實(shí)現(xiàn)而已,調(diào)用native方法與普通Java方法一樣的,調(diào)用代碼如下。

1
2
NDKTest nDKTest = new NDKTest();
nDKTest.calcInNative(1, 2);

native層調(diào)用Java方法

Java數(shù)據(jù)類型的對應(yīng)

在native層調(diào)用Java方法,首先得知道Java類型與native的對應(yīng)關(guān)系,以及Java類型以及方法在native中的簽名格式。

對于基礎(chǔ)類型,對應(yīng)關(guān)系如下。這些數(shù)據(jù)類型的定義全在jni.h中

1
2
3
4
5
6
7
8
9
10
#define JNI_FALSE   0
#define JNI_TRUE    1
typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */

對于非基礎(chǔ)類型,比如String等,Array等統(tǒng)一對應(yīng)jobject對象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};
typedef _jobject*       jobject;
typedef _jclass*        jclass;
typedef _jstring*       jstring;
typedef _jarray*        jarray;
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray*    jbyteArray;
typedef _jcharArray*    jcharArray;
typedef _jshortArray*   jshortArray;
typedef _jintArray*     jintArray;
typedef _jlongArray*    jlongArray;
typedef _jfloatArray*   jfloatArray;
typedef _jdoubleArray*  jdoubleArray;
typedef _jthrowable*    jthrowable;
typedef _jobject*       jweak;

Java類型以及方法簽名

在native中調(diào)用Java層的方法以及屬性的時候需要使用相應(yīng)的簽名表示方法以及屬性,下面就來介紹下基礎(chǔ)類型與引用類型的簽名表示方法。

從上面的表可以看到,基礎(chǔ)類型是使用一個大寫字母表示,對于數(shù)據(jù)則是使用[數(shù)組類型簽名,比如int[]數(shù)組的簽名為[I,一維數(shù)組是一個[,多維數(shù)組就是多個[[[,對于Java中的對象則是L類全路徑;,不要忘記結(jié)尾的;號,對于對于函數(shù)方法則是(參數(shù)一簽名參數(shù)二簽名...)返回值簽名,中間沒有空格。

比如上面的 public native int calcInNative(int num1, int num2);方法的前面為(II)I,其他的類似。

native調(diào)用Java中的方法

首先我們得知道,任何jni的方法都需要通過JNIEnv *env參數(shù)去調(diào)用

1
2
3
4
//C++形式
env->方法名
//C形式
(*env)->方法名

native層調(diào)用Java層方法以及屬性的時候類似于使用反射去調(diào)用Java的方法,基本分為如下幾步。

1、獲取jclass對象(類似于Java中的Class對象)

1
2
3
4
5
6
7
//方法一,通過jobject對象直接獲取
jclass jclass1 = env->GetObjectClass(jobject);
//方法二,通過類描述符獲取
//匿名類使用$號隔開,比如Build中定義的VERSION->android/os/Build$VERSION
env->FindClass(類描述符);
//這里不是Ljava/lang/String;的形式,只有在參數(shù)列表中需要這么寫
jclass cls = env->FindClass("java/lang/String");

2、獲取jmethodID或者jfieldID(類似于Java中的Method或者Field)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//獲取非靜態(tài)方法
//參數(shù)const char *name 方法名
//參數(shù)const char *sig 方法簽名
jmethodID env->GetMethodID(jclass clazz, const char *name, const char *sig)
//獲取靜態(tài)方法
jmethodID env->GetStaticMethodID(jclass clazz, const char *name, const char *sig)
//獲取非靜態(tài)的成員變量
jfieldID env->GetFieldID(jclass clazz, const char *name, const char *sig)
//獲取靜態(tài)的成員變量
jfieldID env->GetStaticFieldID(jclass clazz, const char *name, const char *sig)
//獲取指定類型的成員變量,如下面一個
jboolean env->Get[Type]Field(jobject obj, jfieldID fieldID)
jboolean env->GetBooleanField(jobject obj, jfieldID fieldID)
//獲取指定類型的靜態(tài)成員變量,如下面一個
jboolean env->GetStatic[Type]Field(jclass clazz, jfieldID fieldID)
jboolean env->GetStaticBooleanField(jclass clazz, jfieldID fieldID)

3、調(diào)用相應(yīng)函數(shù)以及獲取/修改屬性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//調(diào)用Java方法
env->Call[Type]Method(...)
jobject env->CallBooleanMethod(jobject obj, jmethodID methodID, ...)
// 調(diào)用Java靜態(tài)方法
env->CallStatic[Type]Method(...)
jboolean env->CallStaticBooleanMethod(jclass clazz, jmethodID methodID, ...)
//獲取Java屬性值
env->Get[Type]Field()
jint env->GetIntField(jobject obj, jfieldID fieldID)
//獲取Java靜態(tài)屬性值
env->GetStatic[Type]Field()
jboolean env->GetStaticBooleanField(jclass clazz, jfieldID fieldID)
//設(shè)置Java屬性值
env->Set[Type]Field()
void env->SetBooleanField(jobject obj, jfieldID fieldID, jboolean value)
//設(shè)置Java靜態(tài)屬性值
env->SetStatic[Type]Field()
void env->SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value)

native調(diào)用舉例

由于本篇博客篇幅已經(jīng)較長,所以這里只給出部分關(guān)鍵代碼。下面為Java層代碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package org.ndk.ndkfirst;
import android.util.Log;
public class NDKTest {
    private static final String TAG = "NDKTest";
    static {
        System.loadLibrary("ndk-test-lib");
    }
    private String mString = "Ndk test string";
    /**
     * 在native中調(diào)用java方法
     */
    public native void callJavaMetood();
    /**
     * 在native中修改對象的字段
     */
    public native void modifyFiled();
/**
* 輸出成員變量的值
*/
    public void outputString() {
        Log.i(TAG, "mString: " + mString);
    }
/**
* 在native中調(diào)用此方法
*/
    @Override
    public String toString() {
        Log.i(TAG, "toString: ");
        return mString;
    }
}

對應(yīng)的native層實(shí)現(xiàn)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <jni.h>
extern "C"
{
JNIEXPORT void JNICALL Java_org_ndk_ndkfirst_NDKTest_callJavaMetood(JNIEnv *env, jobject obj) {
jclass jclass1 = env->GetObjectClass(obj);
jmethodID methodID = env->GetMethodID(jclass1, "toString", "()Ljava/lang/String;");
env->CallObjectMethod(obj, methodID);
}
JNIEXPORT void JNICALL Java_org_ndk_ndkfirst_NDKTest_modifyFiled(JNIEnv *env, jobject obj) {
jclass jclass1 = env->GetObjectClass(obj);
jfieldID fieldID1 = env->GetFieldID(jclass1,"mString","Ljava/lang/String;");
env->SetObjectField(obj,fieldID1,env->NewStringUTF("native modify it"));
}
}

Demo地址:github

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产又粗又猛又大爽又黄| 欧美精品一区二区水蜜桃| 中文字幕日产乱码一区二区| 久久精品少妇内射毛片| 成年人视频日本大香蕉久久| 中文文精品字幕一区二区| 亚洲精品国产福利在线| 一个人的久久精彩视频| 爽到高潮嗷嗷叫之在现观看| 亚洲欧美日韩在线看片| 色婷婷成人精品综合一区| 国产精品美女午夜福利| 国产精品自拍杆香蕉视频| 国产精品欧美一级免费| 欧美一本在线免费观看| 国产精品香蕉在线的人| 欧美成人免费夜夜黄啪啪| 欧美亚洲美女资源国产| 伊人天堂午夜精品草草网| 在线一区二区免费的视频| 欧美日韩视频中文字幕| 午夜亚洲精品理论片在线观看| 国产a天堂一区二区专区| 中文字字幕在线中文乱码二区| 欧美一区二区三区高潮菊竹| 欧美亚洲国产日韩一区二区| 日韩精品中文字幕亚洲| 91偷拍视频久久精品| 日韩人妻有码一区二区| 初尝人妻少妇中文字幕在线| 微拍一区二区三区福利| 老司机精品福利视频在线播放| 欧美午夜一区二区福利视频| 久久99精品日韩人妻| 91日韩在线观看你懂的| 国产又猛又黄又粗又爽无遮挡| 日本高清不卡一二三区| 日韩成人中文字幕在线一区| 91久久国产福利自产拍| 精品女同一区二区三区| 国产一级特黄在线观看|