jni反射java方法

在我们写Android代码时,调用一个类中没有公开的方法,可以进行反射调用,而JNI开发中C++调用java的方法也是反射调用。下面我们就了解一下通过jni中的c++调用java中的方法。

1.类似于我们java中进行反射调用一下,我们得拿到我们的字节码对象
2.通过字节码对象找到方法对象
3.通过对象调用方法,可以调用空参数方法,也可以调用有参数方法,并且将参数通过调用的方法传入,(这里需要将参数变成java对象后才能传入,比如说如果我们要传递一个char *,那么我们需要把它转化为jstring对象)

基本数据类型对应表

Java类型 本地类型 描述
boolean jboolean C/C++8位整型
byte jbyte C/C++带符号的8位整型
char jchar C/C++无符号的16位整型
short jshort C/C++带符号的16位整型
int jint C/C++带符号的32位整型
long jlong C/C++带符号的64位整型
float jfloat C/C++32位浮点型
double jdouble C/C++64位浮点型
Object jobject 任何Java对象,或者没有对应java类型的对象
Class jclass Class对象
String jstring 字符串对象
Object[] jobjectArray 任何对象的数组
boolean[] jbooleanArray 布尔型数组
byte[] jbyteArray 比特型数组
char[] jcharArray 字符型数组
short[] jshortArray 短整型数组
int[] jintArray 整型数组
long[] jlongArray 长整型数组
float[] jfloatArray 浮点型数组
double[] jdoubleArray 双浮点型数组

下面我们就开始写代码,首先拿class对象

//可以通过传入全类名进行查找,注意这里需要把.替换成/
jclass _jclass = env->FindClass("com/test/ndktestapplication/TestBean");

//也可以在已有的对象中获取class对象
jclass _jclass = env -> GetObjectClass(test_bean);

然后我们通过class对象获取到方法ID,这里我们通过GetMethodID这个方法去获取,这里有三个参数 :第1个参数:Java类对象;第2个参数:方法名;第3个参数:该方法的签名。关于方法签名,下面提供一份表格。

Java类型 签名
boolean Z
short S
float F
byte B
int I
double D
char C
long J
void V
引用类型 L + 全限定名 + ;
数组 [+类型签名
//获取构造方法的方法ID,注意构造方法的方法名是"<init>"
jmethodID method_id = env->GetMethodID(_jclass, "<init>","()V");
//获取普通方法的方法ID,注意"()"中是传入参数的参数类型,外面是返回值的类型
jmethodID set_age_id = env->GetMethodID(_jclass,"setAge", "(I)V");

然后调用方法

    jclass _jclass = env->FindClass("com/test/ndktestapplication/TestBean");

    jmethodID method_id = env->GetMethodID(_jclass, "<init>","()V");

    #调用构造方法创建对象
    jobject o = env->NewObject(_jclass, method_id);

    jmethodID set_name_id = env->GetMethodID(_jclass,"setName", "(Ljava/lang/String;)V");
    env->CallVoidMethod(o,set_name_id,name_);

    jmethodID set_age_id = env->GetMethodID(_jclass,"setAge", "(I)V");
    env->CallVoidMethod(o,set_age_id,age);

    env -> ReleaseStringUTFChars(name_,name);
    env -> DeleteLocalRef(_jclass);

上面使用的java类

public class TestBean {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

如果java对象是通过java传递过来的,那么我们可以这么使用

    jclass _jclass = env -> GetObjectClass(test_bean);

    jmethodID get_name_id = env->GetMethodID(_jclass, "getName","()Ljava/lang/String;");
    jstring s = static_cast<jstring>(env->CallObjectMethod(test_bean, get_name_id));

    const char* name = env->GetStringUTFChars(s,0);

这里需要我们注意的是,所有我们在这里创建的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject。如果返回java不必release,java会自己回收。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容