java native interface JNI 调用Java方法
在上一篇文章中介绍了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方法的更多相关文章
- JAVA Native Interface (JNI)
1. Introduction At times, it is necessary to use native (non-Java) codes (e.g., C/C++) to overcome ...
- Java Native Interface调用C++代码
概述 Java Native Interface译为Java原生接口,简称JNI.Java并不是完美的,它的不足体现在运行速度要比传统的C++慢上许多,并且无法直接访问到操作系统底层,为此Java提供 ...
- Java Native Interface 基于JNI的嵌入式手机软件开发实例
1.通过JNI和c/c++的库组件.其他代码交互 2.java和c不能互通的原因时数据类型问题 Introduction https://docs.oracle.com/javase/8/docs/t ...
- +Java中的native关键字浅析(Java+Native+Interface)++
JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的 ...
- Java Native Interface 五 JNI里的多线程与JNI方法的注册
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...
- Java Native Interface 六JNI中的异常
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...
- Java Native Interface 四--JNI中引用类型
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI支持将类实例和数组类型(如jobjec ...
- Java Native Interface 二 JNI中对Java基本类型和引用类型的处理
本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...
- android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )
JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...
随机推荐
- EEPROM的存储大小
学习单片机时,常见的EEPROM如24C02的大小为2Kbit(有的也称2KB).这里的2KB到底能存储多少数据呢? 2KB中,B表示单位bit,K表示1024. 单片机编程中常用的数据类型为unsi ...
- uva11925 Generating Permutations
逆序做,逆序输出 紫书上的描述有点问题 感觉很经典 ans.push_back(2); a.insert(a.begin(),a[n-1]); a.erase(a.end()-1); a.push_b ...
- Vue 2.0 右键菜单组件 Vue Context Menu
Vue 2.0 右键菜单组件 Vue Context Menu https://juejin.im/entry/5976d14751882507db6e839c
- 判断请求是否为ajax
判断请求是否为ajax 转载:http://www.cnblogs.com/tony-jingzhou/archive/2012/07/30/2615612.html x-requested-with ...
- 如何移除不再插入Windows设备的信息
Howto: Remove devices from Windows that are not connected to the system anymore 如何移除不再插入Windows设备的信息 ...
- Linux 编译升级 FFmpeg 步骤
如果服务器已经安装了一个 Ffmpeg 的话,比如已安装在 /usr/local/ffmpeg 目录.Linux下版本升级步骤如下: 1.下载 ffmpeg-*.tar.gz到 Ffmpeg 官网 h ...
- Linux之常用Shell脚本总结
一.简介本文将总结一些常用的shell脚本,方便以后工作中使用. 二.shell脚本[a]定期备份mysql数据库,需结合cronb定时任务调度实现. #!/bin/bash#首先声明一些自定义变量 ...
- freemarker特殊字符输出
期望输出: #{fefefefwewrerwerwrrrre}${fffqqqwwwwwwwwwwwwwwww} 但是以上解析ftl时候会报错!!!!!!!!!!!! 解决办法: 方法1:使用${r& ...
- 解决chrome 批量下载器 mgblihnaaedmhhgadafknogahbgejnno 插件乱码
找到 mgblihnaaedmhhgadafknogahbgejnno\当前版本号(0.0.1_0)\popup.html <html> <head> <meta cha ...
- merge dict key
#!/usr/local/python # -*- coding:utf-8 -*-user_dict = {'python': 23, 'Python': 51, '机器':10, 'PYTHON' ...