JNI 回调实例方法与静态方法
在上一篇中介绍了JNI静态变量。本文是JNI系列的第七篇,介绍JNI中的如何在Native代码调用Java中的方法和静态方法。
系列文章的大纲如下:
JNI 回调实例方法与静态方法
在Native中调用实例方法和静态方法与访问实例变量和静态变量的方法差不多。
只不过现在需要获取的是方法的ID,不再是变量的ID。使用jmethodID 表示。
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
关于类型签名,可以参考JNI 基本类型。
同样获取静态方法的接口:
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
拿到方法的ID之后,就可以使用下面的函数来调用方法了:
NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
其中:
Call<type>Method Routines | NativeType |
---|
CallVoidMethod() | jobject | CallObjectMethod() | jobject | CallBooleanMethod() | jboolean | CallByteMethod() | jbyte | CallCharMethod() | jchar | CallShortMethod() | jshort | CallIntMethod() | jint | CallLongMethod() | jlong | CallFloatMethod() | jfloat | CallDoubleMethod() | jdouble |
Call<type>Method() 、Call<type>MethodA() 和Call<type>MethodV() 之前的区别在于传递参数的形式上的区别。 具体参见下面的实例。
关于jvalue 的定义可以看这里JNI String
NativeType CallStatic<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);
NativeType CallStatic<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
其中:
CallStatic<type>Method Routines | NativeType |
---|
CallStaticVoidMethod() | jobject | CallStaticObjectMethod() | jobject | CallStaticBooleanMethod() | jboolean | CallStaticByteMethod() | jbyte | CallStaticCharMethod() | jchar | CallStaticShortMethod() | jshort | CallStaticIntMethod() | jint | CallStaticLongMethod() | jlong | CallStaticFloatMethod() | jfloat | CallStaticDoubleMethod() | jdouble |
通过下面的实例来加深一下理解。
实例
我们来看一个实例。
这次我们要换一个例子来看了,
package myjni;
public class JNICallbackMethod {
static {
System.loadLibrary("hello");
}
public void callback() {
System.out.println("callback()");
}
public double add(double a, double b) {
return a + b;
}
public static void say(String name) {
System.out.println("hello, " + name);
}
public native void testNative();
public static void main(String[] args) {
new JNICallbackMethod().testNative();
}
}
在Java代码中实现的成员方法callback() 、add() 和静态方法say() 是会被在native的方法 testNative() 中调用的。
如果还不清楚如果生成头文件请参考JNI简介。
生成头文件myjni_JNICallbackMethod.h 的签名为:
JNIEXPORT void JNICALL Java_myjni_JNICallbackMethod_testNative
(JNIEnv *, jobject);
实现函数Java_myjni_JNICallbackMethod_testNative :
JNIEXPORT void JNICALL Java_myjni_JNICallbackMethod_testNative(JNIEnv *env, jobject obj) {
jclass clazz = env->GetObjectClass(obj);
if (clazz == NULL) {
return;
}
jmethodID midCallback = env->GetMethodID(clazz, "callback", "()V");
if (midCallback == NULL) {
return;
}
env->CallVoidMethod(obj, midCallback);
jmethodID midAdd = env->GetMethodID(clazz, "add", "(DD)D");
if (midAdd == NULL) {
return;
}
jdouble result = env->CallDoubleMethod(obj, midAdd, 1.1, 2.2);
std::cout << "1.1 + 2.2 = " << result << std::endl;
jvalue values[2];
values[0].d = 11.1;
values[1].d = 22.2;
result = env->CallDoubleMethodA(obj, midAdd, values);
std::cout << values[0].d << " + " << values[1].d << " = "
<< result << std::endl;
jmethodID midSay = env->GetStaticMethodID(clazz, "say", "(Ljava/lang/String;)V");
if (midSay == NULL) {
return;
}
jstring name = env->NewStringUTF("Furzoom");
env->CallStaticVoidMethod(clazz, midSay, name);
}
编译生成动态库,并运行Java程序得到输出:
callback()
1.1 + 2.2 = 3.3
11.1 + 22.2 = 33.3
hello, Furzoom
vx搜:极客Furzoom,关注获取第一手资料。
本文完。
|