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方法,布布扣,bubuko.com

时间: 2024-10-24 04:28:24

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

Java Programming Tutorial Java Native Interface (JNI)

1.  Introduction At times, it is necessary to use native codes (C/C++) to overcome the memory management and performance constraints in Java. Java supports native codes via the Java Native Interface (JNI). JNI is difficult, as it involves two languag

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

JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了. 使用java与本地已编译的代码交互,通常会丧失平台可移植性.但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件.操作系统进行交互,或者为了

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

JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类库无法满足要求,且在数学运算,实时渲染的游戏上,音视频处理等方面上与C/C++相比效率稍低. 然后,Java语言无法直接操作硬件,C/C++代码不仅能操作硬件而且还能发挥硬件最佳性能. 接着,使用Java调用本地的C/C++代码所写的库,省去了重复开发的麻烦,并且可以利用很多开源的库提高程序效率.

JNI(Java Native Interface)_02

JNI(Java Native Interface)_02 ndk开发常用术语 观察jni.h文件的c语言细节: 交叉编译 在一种平台下编译出能够在另外一种平台下运行二进制代码 平台(1,操作系统:windows linux mac os solaris 2,cpu x86 arm mips) 交叉编译原理 源代码--->编译---->动态库(.dll,.so)-->目标平台运行 windows 源代码编译成 linux,arm下的可执行文件 ndk开发工具 ndk (native de

JNI(Java Native Interface)_03

JNI(Java Native Interface)_03 c/c++区别 jni调用: * c: jstring str = (*env)->NewStringUTF(env,getHello()); * c++:jstring str = (env)->NewStringUTF(getHello()); * 区别如下: * 1,c++中把(*env) 的\*号去掉 * 2,调用函数的时候吧参数env去掉 * 3,c中是结构体 c++是类 * 4,c结构体中的函数指针 c++类的成员函数(c

JNI(Java Native Interface)_01

JNI(Java Native Interface)_01 习惯 1.技术是什么? 2.为什么要使用这个技术? 3.怎么使用? 4.实际怎么应用? jni 是什么 * jni (java native interface) * 两张不同编程语言之间通讯 java: 特点:一次编写,到处运行 java源代码--->.class--->JVM--->os c/c++ 源代码--->os(01) java(中国人)---JNI---c/c++(日本人) jni:两种不同编程语言之间的通讯

Android Jni(Java Native Interface)笔记

首先记录一个问题,关于如何用javah生成头文件的. 总是提示“无法访问android.app.Activity”,网上查了说是要指定android.jar的位置,可以在classpath里指定,也可以在命令中直接指定.在windows下两种都试了,都不行.于是装ubuntu.装ubuntu挺麻烦,一开始想用wubi在windows下安装,失败.后来用了某个启动器在硬盘安装.还有分配swap,根目录/,home目录的大小..真是难倒外行人.安装好了之后试了一下,好像还是不行.. 再百度.在csd

Java採用JNI调用VC++生成的dll(Java与C++交互)

应项目需求,须要android调用java,java再调用C++实现android一个图片匹配的功能,我们作为java组须要和C++和Android进行交互.以下是java和C++採用JNI的方式进行接口传參交互,我做的一个demo并执行成功. 什么是JNI? JNI全拼是Java Native Interface,中文意思为Java本地调用.JNI标准是Java平台的一部分.它同意java和其它语言的代码进行交互.JNI開始是为了本地已经编译好的语言,尤其是C和C++而设计的.我们也能够使用J

coco2dx jni 调用 java 相机返回 图片数据

新建 一个项目 名字:testJin  包名:com.TanSon.org  python命令:python create_project.py -project testJin -package com.TanSon.org -language cpp eclipse 导入项目配置 ... 略去,(可以google) 1 c++ 调用 andriod 1.1 包含头文件 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include <jni.