JNI基础(8): JNI调用Java方法
2022-01-12 本文已影响0人
MemetGhini
8.1 JNI调用Java类的成员方法和静态方法
首先需要了解一下java方法在jni中签名格式。简单来说: (参数签名直接拼接)返回值类型的签名
。例如:
Point test(int x,float y) --> (IF)Ljava/awt/Point;
Object[] test(byte x,char y) --> (BC)[Ljava/lang/Object;
String fun(); --> ()Ljava/lang/String;
long f(int I, Class c); --> (ILjava/lang/Class;)J
void f(byte[] bytes); --> ([B)V
JNI中调用java方法为如下三个步骤:
- env->GetObjectClass(xxx) 找到类jclass
- env->Get[Static(静态或者非静态)]MethodID(...) 找到方法id
- env->Call[Void/Object/Boolen(返回值类型)]Method(obj, jmid, ...); 来调用方法
例如我们为Person添加如下方法:
public void callInstanceMethod(int num)
{
Log.i("JNI-MG", "instance method called with : num = " + num);
}
public static String callStaticMethod(String str)
{
Log.i("JNI-MG", "static called with : " + str);
return "static return" + str;
}
public static String callStaticMethod(String[] strs, int num)
{
if (strs != null)
{
for (String str : strs)
{
Log.i("JNI-MG", "static called with : " + str);
}
}
Log.i("JNI-MG", "static called with num : " + num);
return "static return with num = " + num;
}
在默认工程MainActivity中添加public static native void callFromNative(Person person);
并在JNI中进行调用验证:
extern "C"
JNIEXPORT void JNICALL
Java_com_memetghini_javaobject_MainActivity_callFromNative(JNIEnv *env, jclass clazz, jobject person) {
//调用非静态方法
//首先找到类
jclass cls = env->GetObjectClass(person);
//再找到该类的方法id
jmethodID jmid = env->GetMethodID(cls, "callInstanceMethod", "(I)V");
//然后调用
env->CallVoidMethod(person, jmid, 99);
//调用静态方法
//上面已经找打类,接下来直接找到方法id
jmethodID jmid2 = env->GetStaticMethodID(cls, "callStaticMethod", "(Ljava/lang/String;)Ljava/lang/String;");
jstring s = (jstring)env->CallStaticObjectMethod(cls, jmid2, env->NewStringUTF("Kadi"));
const char* cc = env->GetStringUTFChars(s, 0);
LOGI("java 返回的 : %s", cc);
env->ReleaseStringUTFChars(s, cc);
//调用静态方法with数组
jmethodID jmid3 = env->GetStaticMethodID(cls, "callStaticMethod", "([Ljava/lang/String;I)Ljava/lang/String;");
//构造参数
jclass strClass = env->FindClass("java/lang/String");
int size = 3;
jobjectArray obj_array = env->NewObjectArray(size, strClass, nullptr);
jstring strItem;
for (int i = 0; i < size; ++i)
{
strItem = env->NewStringUTF("Test String");
env->SetObjectArrayElement(obj_array, i, strItem);
}
env->CallStaticObjectMethod(cls, jmid3, obj_array, 1);
}
8.2 JNI 访问Java类的构造方法
在JNI中创建java类的流程跟调用普通方法是一样的,比较特殊的地方是构造方法名为<init>
,没有返回值。
例如构造Person类并返回:
//方式1
jclass cls = env->FindClass("com/memetghini/javaobject/Person");
jmethodID mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
jstring js = env->NewStringUTF("MemetGhini");
jobject obj = env->NewObject(cls, mid, js); //直接new一个对象
return obj;
//方式二
jclass cls = env->FindClass("com/memetghini/javaobject/Person");
jmethodID mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
jstring js = env->NewStringUTF("MemetGhini 2222");
jobject obj = env->AllocObject(cls);//先开辟内存 在调用构造方法
env->CallVoidMethod(obj, mid, js);
8.3 JNI中访问父类的方法
调用被子类覆盖的父类方法需要用env->CallNonvirtualVoidMethod(obj, cls, mid);
方法。cls需要传父类的class即可。相当于java中的super.func()
调用。
例如:创建一个class叫Son 继承自 Person
public class Son extends Person {
public Son(String name) {
super(name);
}
public void run() {
Log.i("JNI-MG", "Son run。");
}
}
并在父类Person中也实现run() 方法:
public void run() {
Log.i("JNI-MG", "Person run。");
}
在默认工程MainActivity中添加JNI方法声明public static native void callFatherFun(Son son);
参数为son,我们在jni中实现调用父类的run方法。
extern "C"
JNIEXPORT void JNICALL
Java_com_memetghini_javaobject_MainActivity_callFatherFun(JNIEnv *env, jclass clazz, jobject son) {
//查找父类的类jclass
jclass cls = env->FindClass("com/memetghini/javaobject/Person"); //父类的class
//如果调用son的run方法需要查找son的类
//jclass cls = env->GetObjectClass(son);
//查找方法id
jmethodID mid = env->GetMethodID(cls, "run", "()V");
//通过CallNonvirtualVoidMethod调用
env->CallNonvirtualVoidMethod(son, cls, mid);
}