在上一篇文章中介绍了JNI。以及java调用JNI。这篇讲一下 JNI调用java方法。

通过使用合适的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对象的实例

jclass cls = (*env)->FindClass(env, "Lpackagename/classname;");  //创建一个class的引用

jmethodID id = (*env)->GetMethodID(env, cls, "", "(D)V");  //注意这里方法的名称是"",它表示这是一个构造函数。并且构造參数是double型的

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的定义例如以下:

jclass cls = (*env)->FindClass(env, "Lpackagename/classname;");  //创建一个class的引用

   jmethodID id = (*env)->GetMethodID(env, cls, "", "(D)V");  //注意这里方法的名称是"",它表示这是一个构造函数。      并且构造參数是double型的

    jobject obj = (*env)->NewObjectA(env, cls, id, args);  //获得一实例。args是构造函数的參数,它是一个jvalue*类型。

第一个变量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对象的类:

jclass cls = (*env)->GetObjectClass(env, obj);       // 使用GetObjectClass方法获取obj相应的jclass。 

jclass cls = (*env)->FindClass(“android/util/log”) // 直接搜索类名,须要是static修饰的类。

2、获取MethodID:

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

其參数的意义: 

env-->JNIEnv 

cls-->第一步获取的jclass 

"callback"-->要调用的方法名 

"(I)V"-->方法的Signature, 签名同前面的JNI规则。

3、调用方法:

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

使用CallVoidMethod方法调用方法。參数的意义: 

env-->JNIEnv 

obj-->通过本地方法穿过来的jobject 

mid-->要调用的MethodID(即第二步获得的MethodID) 

depth-->方法须要的參数(相应方法的需求,加入相应的參数)

注:这里使用的是CallVoidMethod方法调用,由于没有返回值,假设有返回值的话使用相应的方法。在后面会提到。

CallVoidMethod                   CallStaticVoidMethod

CallIntMethod                     CallStaticVoidMethod

CallBooleanMethod              CallStaticVoidMethod

CallByteMethod                   CallStaticVoidMethod

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*互转的方法:

/* c/c++ string turn to java jstring */

jstring charToJstring(JNIEnv* env, const char* pat)

{

jclass     strClass = (*env)->FindClass(env, "java/lang/String");

jmethodID  ctorID   = (*env)->GetMethodID(env, strClass, "", "([BLjava/lang/String;)V");

jbyteArray bytes    = (*env)->NewByteArray(env, strlen(pat));

(*env)->SetByteArrayRegion(env, bytes, 0, strlen(pat), (jbyte*)pat);

jstring    encoding = (*env)->NewStringUTF(env, "UTF-8");

return (jstring)(*env)->NewObject(env, strClass, ctorID, bytes, encoding);

}





/* java jstring turn to c/c++ char* */

char* jstringToChar(JNIEnv* env, jstring jstr)

{       

    char* pStr = NULL;

    jclass     jstrObj   = (*env)->FindClass(env, "java/lang/String");

    jstring    encode    = (*env)->NewStringUTF(env, "utf-8");

    jmethodID  methodId  = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");

    jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);

    jsize      strLen    = (*env)->GetArrayLength(env, byteArray);

    jbyte      *jBuf     = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);

    if (jBuf > 0)

    {

        pStr = (char*)malloc(strLen + 1);

        if (!pStr)

        {

            return NULL;

        }

        memcpy(pStr, jBuf, strLen);

        pStr[strLen] = 0;

    }

    env->ReleaseByteArrayElements(byteArray, jBuf, 0);

    return pStr;

}

事实上在JNI中调用java的特性和在java中区别不大都是同样思想,比方先找类。再找构造,再创建对象。然后就进行一系列操作...等等。

參考:http://zhiweiofli.iteye.com/blog/1830321

如有问题请留言,转载注明出处。

java native interface JNI 调用Java方法的更多相关文章

  1. JAVA Native Interface (JNI)

    1.  Introduction At times, it is necessary to use native (non-Java) codes (e.g., C/C++) to overcome ...

  2. Java Native Interface调用C++代码

    概述 Java Native Interface译为Java原生接口,简称JNI.Java并不是完美的,它的不足体现在运行速度要比传统的C++慢上许多,并且无法直接访问到操作系统底层,为此Java提供 ...

  3. Java Native Interface 基于JNI的嵌入式手机软件开发实例

    1.通过JNI和c/c++的库组件.其他代码交互 2.java和c不能互通的原因时数据类型问题 Introduction https://docs.oracle.com/javase/8/docs/t ...

  4. +Java中的native关键字浅析(Java+Native+Interface)++

    JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的 ...

  5. Java Native Interface 五 JNI里的多线程与JNI方法的注册

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...

  6. Java Native Interface 六JNI中的异常

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...

  7. Java Native Interface 四--JNI中引用类型

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI支持将类实例和数组类型(如jobjec ...

  8. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  9. android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )

    JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...

随机推荐

  1. 图片充当li标签列表标志

    默认情况下,浏览器使用一个黑圆圈作为列表标志,可以用图片取代它: ul {list-style: none} ul li{ background-image: url("img/logo_0 ...

  2. 用固定长度的数组实现stack queue

    package my_basic.class_3; /** * 用数组结构实现大小固定的队列和栈 */ public class Code_01_Array_stack_queue { public ...

  3. WebGL 绘制Line的bug(一)

    今天说点跟WebGL相关的事儿,不知道大家有没有碰到过类似的烦恼. 熟悉WebGL的同学都知道,WebGL绘制模式有点.线.面三种:通过点的绘制可以实现粒子系统等,通过线可以绘制一些连线关系:面就强大 ...

  4. linux wget变成000权限

    今天使用wget下载文件时出现:-bash: /usr/bin/wget: 权限不够. 查看  /usr/bin/wget 的权限为: ---------- 1 root root 357400 3月 ...

  5. vue 指令---气泡提示(手撸实战)

    菜鸟学习之路//L6zt github 自己在造组件轮子,也就是瞎搞.自己写了个slider组件,想加个气泡提示.为了复用和省事特此写了个指令来解决.预览地址项目地址 github 我叫给它胡博 cs ...

  6. 条款28:避免返回handles指向对象内部的成分(Avoid returning "handles" to objects internals)

    NOTE: 1.避免返回handles(包括references 指针 迭代器)指向对象内部.遵守这个条款可增加分装性,帮助const 成员函数的行为像个const,并将发生“虚吊号码牌”(dangl ...

  7. 如何在小程序实现图片lazy-load懒加载效果

    自从跳一跳出现之后小程序又开始频繁出现了,在学习过程中发现小程序虽然好但是由于api不完善导致开发过程中有很多的坑,重点是网上相对小程序出现坑时解决方案显然比较少,小程序最让人觉得痛心疾首之一就是无法 ...

  8. python019 Python3 File(文件) 方法

    file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数: 序号 方法及描述 1 file.close() 关闭文件.关闭后文件不能再进行读写操作. 2 file.flush() ...

  9. bzoj1202:[HNOI2005]狡猾的商人 【并查集】

    Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 ...

  10. 洛谷P1021 邮票面值设计

    题目描述 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1-MAX之间的每一个邮资值都能得到 ...