NDK学习之JNI中关于Object一些列操作

今天我们学习的是在JNI中对Object的操作,如果使用java,我们可以通过创建一个对象,通过一个引用来接收,比如父类引用指向子类对象,然后拿到这个对象引用可以对其进行一些列的操作。在JNI中我们也可以创建并对其Object做一些列的操作。
在这之前需要引入几个概念JNIEnv、jobject,因为在后面我们会频繁的使用这两个类型。

  1. JNIEnv:指向一个结构体,可以理解为java和C/C++之间的翻译官。
  2. jobject:如果native方法不是static的话,这个obj就代表这个native方法的类实
    例如果native方法是static的话,这个obj就代表这个native方法的类的class对象实例。

了解了这两个类型以后我们开始真正的本文的学习——JNI对Object的操作。

首先我们先介绍通过分配的方式获取一个对象——也可以理解成复制。
按例先创建一个Test类

public class Test { 
  public void temp() {
      Log.e("TAG", "我是text类中的temp方法");
  }
}

然后我们在MainActivity中创建一个native方法

public class MainActivity extends AppCompatActivity {
Test test = new Test();

// Used to load the 'native-lib' library on application startup.
static {
    System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Example of a call to a native method
    TextView tv = (TextView) findViewById(R.id.sample_text);
    tv.setText(stringFromJNI());
     testObject(test);//调用native方法
}

public native String stringFromJNI();

public native void testObject(Test test);
}

在testObject报红处我们在native-lib.cpp文件生成native方法,进行我们操作

extern "C"
JNIEXPORT void JNICALL
Java_com_captain_wudongsheng_day3ndk_MainActivity_testObject(JNIEnv  *env,  /*native方法class对象,也就是我们的MainActivity*/ jobject instance,
                                                       /*传入的对象*/  jobject test) {
  /*分配一个对java象*/
  jclass testclass = env->FindClass("com/captain/wudongsheng/day3ndk/Test");//通过反射的机制拿到Test类,注意通过这种方法不会调用构造函数
  jobject testobject = env->AllocObject(testclass);

  /*jmethodID GetMethodID(jclass clazz /*类*/, const char* name/*方法名*/, const char* sig/*方法签名*/)*/
  jmethodID temmid = env->GetMethodID(testclass, "temp", "()V");//获取方法methodID
  env->CallVoidMethod(testobject, temmid);//指向Call方法

}

运行以后 我们可以顺利在控制台看到日志输出,执行了temp()方法.

10-30 16:53:00.501 2524-2524/com.captain.wudongsheng.day3ndk E/TAG: 我是text类中的temp方法

有一点需要注意:
当Local Reference(局部引用)不再使用的时候 最好调用void DeleteLocalRef(jobject localRef),原因是创建了过多的 Local Reference,从而导致 out of memory。实际上,nativeMethod 在运行中创建了越来越多的 JNI Local Reference,而不是看似的始终只有一个。过多的 Local Reference,导致了 JNI 内部的 JNI Local Reference 表内存溢出,有兴趣的同学可以for循环试一下。

还有种方式创建一个java对象,通过NewObjec(jclass clazz, jmethodID methodID, ...)
其中第二个参数是构造函数名ID,固定的写法是<init>
,第三个参数方法的参数列表。

 /*创建一个java对象*/
jmethodID testmid = env->GetMethodID(testclass,/*构造方法的函数名的固定方法*/"<init>","(I)V");
jobject newobject = env->NewObject(testclass, /*构造方法的ID*/testmid);

通过上边两种方法获取的对象是什么类型呢,可以用 JNI 1.6引进的方法
jobjectRefType GetObjectRefType(jobject obj)获取对象引用的类型。

 /*返回obj参数对象的引用的类型*/
jobjectRefType allcotype = env->GetObjectRefType(allocobject);
jobjectRefType newtype = env->GetObjectRefType(newobject);
LOGE("allcotype=%d newtype=%d",allcotype,newtype);

那么jobjectRefType是个什么东西呢,进入jni.h头文件中可以看到,其实就是定义了一个枚举

typedef enum jobjectRefType {
  JNIInvalidRefType = 0//obj参数不是一个有效的引用
  JNILocalRefType = 1,//obj参数是一个局部引用
  JNIGlobalRefType = 2, //obj参数是一个全局引用
  JNIWeakGlobalRefType = 3. //obj参数是一个弱全局引用
} jobjectRefType;

通过Log打印,也能看出是个局部引用

  10-30 17:53:16.316 3316-3316/com.captain.wudongsheng.day3ndk E/JNI: (/Users/wudongsheng/Downloads/Day3NDK/app/src/main/cpp/native-lib.cpp:78) void Java_com_captain_wudongsheng_day3ndk_MainActivity_testObject(JNIEnv *, jobject, jobject): allcotype=1 newtype=1

接下来我们学习的是Object是否可以强转成clazz对象,这时候我们需要一个
jboolean IsInstanceOf(jobject obj, jclass clazz)方法,返回值是一个jboolean

jboolean allj = env->IsInstanceOf(allocobject, testclass);
jboolean newJ = env->IsInstanceOf(newobject, testclass);

jboolean allj1 = env->IsInstanceOf(allocobject, clazz);//clazz是我们通过native方法传进来的对象
jboolean newJ1 = env->IsInstanceOf(newobject, clazz);
//PS:如果一个对象是NULL,可以强转成任何class对象,
LOGE("%d %d %d %d",allj,newJ,allj1,newJ1);

查看log日志:输出的是1 1 0 0,你复制的对象和new出来的对象肯定和传入的对象不一样

10-30 17:53:16.316 3316-3316/com.captain.wudongsheng.day3ndk E/JNI: (/Users/wudongsheng/Downloads/Day3NDK/app/src/main/cpp/native-lib.cpp:96) void Java_com_captain_wudongsheng_day3ndk_MainActivity_testObject(JNIEnv *, jobject, jobject): 1 1 0 0

最后还有一个知识点,检查两个引用是否引用相同的java对象
jboolean IsSameObject(jobject ref1, jobject ref2)

jfieldID jtestID = env->GetFieldID(clazz, "test", "Lcom/captain/wudongsheng/day3ndk/Test;");//获取fieldID
jobject testJobject = env->GetObjectField(instance, jtestID);//获取ObjectField
//test 是传入的对象 testJobject通过ID拿到的对象
jboolean jsameObject1 = env->IsSameObject(test, testJobject);//
jboolean jsameObject2 = env->IsSameObject(test, allocobject);//复制对象
jboolean jsameObject3 = env->IsSameObject(test, newobject);//创建新对象
jboolean jsameObject4 = env->IsSameObject(allocobject, testJobject);
jboolean jsameObject5 = env->IsSameObject(allocobject, newobject);
jboolean jsameObject6 =  env->IsSameObject(testJobject, newobject);

LOGE("%d %d %d %d %d %d",jsameObject1,jsameObject2,jsameObject3,jsameObject4,jsameObject5,jsameObject6);

最后日志输出的结果是:

10-30 17:53:16.316 3316-3316/com.captain.wudongsheng.day3ndk E/JNI: (/Users/wudongsheng/Downloads/Day3NDK/app/src/main/cpp/native-lib.cpp:110) void Java_com_captain_wudongsheng_day3ndk_MainActivity_testObject(JNIEnv *, jobject, jobject): 1 0 0 0 0 0

可以看出只有第一个是相同的java对象,test是从MainActivity中传入的,而testJobject是通过GetObjectField从MainActivity中拿到的,显然是同一个对象。
最后多出了两个方法:

  1. jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
  2. jobject GetObjectField(jobject obj, jfieldID fieldID)

这也是下一篇博客要学习的内容,哪今天这篇博客就到这了。

NDK开发从入门到——??

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容