这次在做NDK开发的时候,有需求需要在JNI直接调用和获取Java中的方法和变量,比如回调,系统信息参数等…
在JNI中调用Java方法,就需要使用FindClassGetMethodID这两个类

使用FindClass和GetMethodID调用Java方法

先上一个简单调用Java方法的例子:
我们有一个数学工具类包名是com.andy.obj,里面有一个加法的静态方法和一个减法的普通方法,

import com.andy.obj;

public class MathUtil {
	public static int add(int a, int b) {
		return a+b;
	}
	
	public int reduce(int a,int b) {
		return a-b;
	}
}

首先在JNI中可以通过FindClass可以找到Java类,得到jclass,例如:

jclass javaclass = env->FindClass("com/andy/obj/MathUtil");

FindClass的参数需要传入类的完整包名。

使用GetMethodID可以获取类的方法,得到jmethodID,例如:

jmethodID jstaticmethodIds = env->GetMethodID(javaclass, "add", "(II)I");
jmethodID jmethodIds = env->GetMethodID(javaclass, "reduce", "(II)I");

其中第四个参数是比较奇怪的字符串,这就是方法签名,现在只需要知道是设置了Java原生方法的两个int类型的参数和一个int类型的返回值,具体用法和作用后面细讲

调用Java方法

//调用静态方法
 env->CallStaticObjectMethod(javaclass, jstaticmethodIds, 1,1);
 jobject object = env->AllocObject(jclazz);
 //调用普通方法
 env->.CallIntMethod(javaclass, jmethodIds, 1,1);

上总流程

extern "C"
JNIEXPORT void JNICALL
Java_com_andy_obj_test_add(JNIEnv *env, jobject jobj) {
    //得到字节码
    jclass javaclass = env->FindClass("com/andy/obj/MathUtil");
    //得到普通方法
    jmethodID jmethodIds = env->GetMethodID(jclazz,"reduce","(II)I");
    //得到静态普通方法
    jmethodID jstaticmethodIds = env->GetStaticMethodID(jclazz,"add","(II)I");
	//调用静态方法
	env->CallStaticObjectMethod(env, javaclass, jstaticmethodIds,1,1);
    //调用普通方法需要实例化
    jobject object = env->AllocObject(jclazz);
    //调用普通方法
    env->CallIntMethod(object,jmethodIds,100,1);
}

方法签名

GetMethodID中第四个参数()V就是方法签名,Java是支持重载的,所以需要标明方法的传参和返回值,这就是方法的签名。它是用来保证方法的唯一性。其中()代表不传参数,V代表返回值为void。
方法签名对于Java的类型都有一一对应的值。方法签名中用大写的字母对应了java的基本数据类型:

  • Z -> boolean
  • B -> byte
  • C -> char
  • S -> short
  • I -> int
  • J -> long
  • F -> float
  • D -> double

其实就是有两个比较特殊的:boolean对应的是Z,long对应的J,其他的都是首个字母的大写即可。

数组的表示方法,以[为标志,一个[标识一维数组,[[表示二维数组,例如:

  • byte[] -> [B
  • int[][] -> [[I

引用类型的表示方法,需要以L开头,以;结束,中间对应类型的包名加类名,例如:

  • String -> Ljava/lang/String;
  • Object -> Ljava/lang/Object;

自定义类的表示方法类似,比如包名为com.andy.obj,类名为MethodBean的表示方法是:

  • com.andy.obj.MethodBean ->Lcom.andy.obj.MethodBean;