通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。
下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldID或jmethodID。

函数  描述
GetFieldID  得到一个实例的域的ID
GetStaticFieldID  得到一个静态的域的ID
GetMethodID 得到一个实例的方法的ID
GetStaticMethodID 得到一个静态方法的ID

构造一个Java对象的实例

  1. jclass cls = (*env)->FindClass(env, "Lpackagename/classname;");  //创建一个class的引用
  2. jmethodID id = (*env)->GetMethodID(env, cls, "", "(D)V");  //注意这里方法的名称是"",它表示这是一个构造函数,而且构造参数是double型的
  3. jobject obj = (*env)->NewObjectA(env, cls, id, args);  //获得一实例,args是构造函数的参数,它是一个jvalue*类型。

首先是获得一个Java类的class引用 (*env)->FindClass(env, "Lpackagename/classname;");  请注意参数:Lpackagename/classname; ,L代表这是在描述一个对象类型,packagename/classname是该对象耳朵class路径,请注意一定要以分号(;)结束!

然后是获取函数的id,jmethodID id = env->GetMethodID(cls, "", "(D)V");  第一个是刚刚获得的class引用,第二个是方法的名称,最后一个就是方法的签名

还是不懂?我曾经如此,请接着看...

难理解的函数签名

JNINativeMethod的定义如下:

  1. typedef struct {
  2. const char* name;
  3. const char* signature;
  4. void* fnPtr;
  5. } JNINativeMethod;

第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数。

其中比较难以理解的是第二个参数,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"

实际上这些字符是与函数的参数类型一一对应的。
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);

 

那其他情况呢?请查看下表:

类型
符号
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
object对象 LClassName;      L类名;
Arrays
[array-type        [数组类型
methods方法 (argument-types)return-type     (参数类型)返回类型

稍稍补充一下:

1、方法参数或者返回值为java中的对象时,签名中必须以“L”加上其路径,不过此路径必须以“/”分开,自定义的对象也使用本规则

比如说 java.lang.String为“java/lang/String”,com.nedu.jni.helloword.Student为"Lcom /nedu/jni/helloword/Student;"

2、方法参数或者返回值为数组类型时,请前加上[

例如[I表示 int[],[[[D表示 double[][][],即几维数组就加几个[

在本地方法中调用Java对象的方法

1、获取你需要访问的Java对象的类:

  1. jclass cls = (*env)->GetObjectClass(env, obj);       // 使用GetObjectClass方法获取obj对应的jclass。
  2. jclass cls = (*env)->FindClass(“android/util/log”) // 直接搜索类名,需要是static修饰的类。

2、获取MethodID:

  1. jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V"); //GetStaticMethodID(…),获取静态方法的ID使用GetMethdoID方法获取你要使用的方法的MethdoID

其参数的意义:
env-->JNIEnv
cls-->第一步获取的jclass
"callback"-->要调用的方法名
"(I)V"-->方法的Signature, 签名同前面的JNI规则。

3、调用方法:

  1. (*env)->CallVoidMethod(env, obj, mid, depth);// CallStaticIntMethod(….) , 调用静态方法

使用CallVoidMethod方法调用方法。参数的意义:
env-->JNIEnv
obj-->通过本地方法穿过来的jobject
mid-->要调用的MethodID(即第二步获得的MethodID)
depth-->方法需要的参数(对应方法的需求,添加相应的参数)

注:这里使用的是CallVoidMethod方法调用,因为没有返回值,如果有返回值的话使用对应的方法,在后面会提到。

  1. CallVoidMethod                   CallStaticVoidMethod
  2. CallIntMethod                     CallStaticVoidMethod
  3. CallBooleanMethod              CallStaticVoidMethod
  4. CallByteMethod                   CallStaticVoidMethod

现在稍稍明白文章开始构造Java对象那个实例了吧?让我们继续深入一下:

Jni操作Java的String对象

从java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char*不同,所以如果你直接当做char*使用的话,就会出错。因此在使用之前需要将jstring转换成为c/c++中的char*,这里使用JNIEnv提供的方法转换。

const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
(*env)->ReleaseStringUTFChars(env, jstr, str);

这里使用GetStringUTFChars方法将传进来的prompt(jstring类型)转换成为UTF-8的格式,就能够在本地方法中使用了。
注意:在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出。

下面是Jni访问String对象的一些方法:

  • GetStringUTFChars          将jstring转换成为UTF-8格式的char*
  • GetStringChars               将jstring转换成为Unicode格式的char*
  • ReleaseStringUTFChars    释放指向UTF-8格式的char*的指针
  • ReleaseStringChars         释放指向Unicode格式的char*的指针
  • NewStringUTF               创建一个UTF-8格式的String对象
  • NewString                    创建一个Unicode格式的String对象
  • GetStringUTFLength      获取UTF-8格式的char*的长度
  • GetStringLength           获取Unicode格式的char*的长度

下面提供两个String对象和char*互转的方法:

    1. /* c/c++ string turn to java jstring */
    2. jstring charToJstring(JNIEnv* env, const char* pat)
    3. {
    4. jclass     strClass = (*env)->FindClass(env, "java/lang/String");
    5. jmethodID  ctorID   = (*env)->GetMethodID(env, strClass, "", "([BLjava/lang/String;)V");
    6. jbyteArray bytes    = (*env)->NewByteArray(env, strlen(pat));
    7. (*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), (jbyte*)pat);
    8. jstring    encoding = (*env)->NewStringUTF(env, "UTF-8");
    9. return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);
    10. }
    11. /* java jstring turn to c/c++ char* */
    12. char* jstringToChar(JNIEnv* env, jstring jstr)
    13. {
    14. char* pStr = NULL;
    15. jclass     jstrObj   = (*env)->FindClass(env, "java/lang/String");
    16. jstring    encode    = (*env)->NewStringUTF(env, "utf-8");
    17. jmethodID  methodId  = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");
    18. jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);
    19. jsize      strLen    = (*env)->GetArrayLength(env, byteArray);
    20. jbyte      *jBuf     = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);
    21. if (jBuf > 0)
    22. {
    23. pStr = (char*)malloc(strLen + 1);
    24. if (!pStr)
    25. {
    26. return NULL;
    27. }
    28. memcpy(pStr, jBuf, strLen);
    29. pStr[strLen] = 0;
    30. }
    31. env->ReleaseByteArrayElements(byteArray, jBuf, 0);
    32. return pStr;
    33. }

本地代码中使用Java对象的更多相关文章

  1. hibernate中的java对象有几种状态,其相互关系如何(区别和相互转换)。

    hibernate中的java对象有几种状态,其相互关系如何(区别和相互转换). 解答:在Hibernate中,对象有三种状态:临时状态.持久状态和游离状态. 临时状态:当new一个实体对象后,这个对 ...

  2. 在MySQL中保存Java对象

    需要在MySQL中保存Java对象. 说明: 对象必须实现序列化 MySQL中对应字段设置为blob 将Java对象序列化为byte[] public static byte[] obj2byte(O ...

  3. Java中JNI的使用详解第四篇:C/C++中创建Java对象和String字符串对象及对字符串的操作方法

    首先来看一下C/C++中怎么创建Java对象:在JNIEnv中有两种方法是用来创建Java对象的: 第一种方法: jobject  NewObject(jclass clazz  , jmethodI ...

  4. 本地C代码中创建Java对象

    作者:唐老师,华清远见嵌入式学院讲师. 创建Java域的对象就是创建Java类的实例,再调用Java类的构造方法. 以Bitmap的构建为例,Bitmap中并没有Java对象创建的代码及外部能访问的构 ...

  5. Java 对象在堆中的内存结构

    翻译人员: 铁锚 翻译日期: 2013年11月8日 原文链接:  What do Java objects look like in memory during run-time? 我们知道,函数每次 ...

  6. Android NDK开发之Jni调用Java对象

    https://my.oschina.net/zhiweiofli/blog/114064 通过使用合适的JNI函数,你可以创建Java对象,get.set 静态(static)和 实例(instan ...

  7. Java对象的序列化和反序列化实践

    2013-12-20 14:58 对象序列化的目标是将对象保存在磁盘中,或者允许在网络中直接传输对象.对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存 ...

  8. 【toplink】 位居第一的Java对象关系可持续性体系结构

    TopLink,是位居第一的Java对象关系可持续性体系结构,原署WebGain公司的产品,后被Oracle收购,并重新包装为Oracle AS TopLink.TOPLink为在关系数据库表中存储 ...

  9. java 对象序列化 RMI

    对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中.JVM停止之后,这些状态就丢失了.在很多情况下,对象的内部状态是需要被持久化下来的.提到持久化,最直接的做法是保存到文件系统或是数 ...

随机推荐

  1. spring boot启动原理步骤分析

    spring boot最重要的三个文件:1.启动类 2.pom.xml 3.application.yml配置文件 一.启动类->main方法 spring boot启动原理步骤分析 1.spr ...

  2. Maven多模块项目搭建

    最近一直在思考如何能够更好的重用代码.减少重复劳动,之前有一篇文章通过导入JAR包的形式,可以重用部分形如util类的方法,但是这样的话,管理起来jar包,特别是协同工作,多项目情况下,管理JAR会出 ...

  3. BestCoder Round #52 (div.2) HDU 5418 Victor and World (DP+状态压缩)

    [题目链接]:pid=5418">click here~~ [题目大意]: 问题描写叙述 经过多年的努力,Victor最终考到了飞行驾照. 为了庆祝这件事,他决定给自己买一架飞机然后环 ...

  4. Woody的Python学习笔记2

    Python多行语句 Python语句中一般以新行作为语句的结束符.但我们能够使用斜杠(\)将一行的语句分为多行显示,例如以下所看到的: total = item_one+\ item_two + \ ...

  5. HDU 1040.As Easy As A+B【排序】【如题(水!水!水!)】【8月24】

    As Easy As A+B Problem Description These days, I am thinking about a question, how can I get a probl ...

  6. Python菜鸟晋级12----多线程

    Python 多线程 多线程类似于同一时候执行多个不同程序,多线程执行有例如以下长处: 使用线程能够把占领长时间的程序中的任务放到后台去处理. 用户界面能够更加吸引人.这样比方用户点击了一个butto ...

  7. Http抓包工具--查尔斯

    查尔斯 查尔斯:http://www.charlesproxy.com/ 这是比較好用的抓包工具.有Mac.Windows.Linux版本号.能够相应用程序.浏览器.手机.手机模拟器进行抓包. 官方站 ...

  8. matplotlib 可视化 —— matplotlib.patches

    官方帮助文档 patches - Matplotlib 1.5.1 documentation patches 下主要包含的常用图形类有: Eclipse Circle Wedge 1. plt.gc ...

  9. rsync来传输文件(可断点续传)

    scp传文件的话如果出错就得重新来过, 用rsync可以实现断点上传的功能   大概就是这样用:  rsync -P --rsh=ssh home.tar 192.168.205.34:/home/h ...

  10. 10 quick tips for Redis

    Redis is hot in the tech community right now. It's come a long way from being a small personal proje ...