2.本地代码调用Java代码

2023-04-14  本文已影响0人  BUG弄潮儿

1. 本地代码访问Java代码

JNIEXPORT void JNICALL Java_com_omg_NativeLib_sayHello (JNIEnv *env, jobject jobj){
    cout << "hello world" << endl;
}

2. JNIEnv 类型

NewObject / NewString / New<TYPE>Array
Get<TYPE>Field / Set<TYPE>Field
GetStatic<TYPE>Field / SetStatic<TYPE>Field
Call<TYPE>Method / CallStatic<TYPE>Method

等许许多多的函数

不是静态方式时,传入的是当前关联的类对象

静态方法时,传入当前类的Class对象

3. Java的类型在C/C++中的映射关系

Java类型 本地类型 JNI定义的别名
int long jint / jsize
long __int64 jlong
byte signed char jbyte
boolean unsigned char jboolean
char unsigned short jchar
short short jshort
float float jfloat
double double jdouble
Object _jobject* jobject

4. jclass如何获取

jclass FindClass(const char* clsName);
jclass GetObjectClass(jobject ojb);
jclass GetSuperClass(jclass obj);

在Java JDK中也有这几个方法

jclass cls_str = env->FindClass("java/lang/String");

5. 访问Java类中的属性与方法

使用JNIEnv的

GetFieldID / GetMethodID
GetStaticFieldID / GetStaticMethodID

来取得相应的jfieldID和jmethodID

来看下方法定义

jfieldID GetFieldID(jclass clazz, const char *name, const char *sig);

jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);

jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig);

jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig);

如:env -> GetMethodID(data_Clazz, "<init>", "()V");

6. Sign是什么?

例如:TestNative类中有两个重载的方法

package com.omg;

public class TestNative {

    public void function( int i ){
        System.out.println("Integer: " + i);
    }

   public void function( double d ){
        System.out.println("double: " + d);
    }
}

然后再C/C++代码中调用其中的一个function方法的话;

//首先取得要调用的方法所在的类
jclass clazz_TestNative = env->FindClass("com/omg/TestNative");
//获取jmethodID之后才能进行调用
jmethodID id_func = env->GetMethodID(clazz_TestNative, "function", ??);

但是到底取得的是 void function(int i) 方法还是 void function(double d) 方法的jmethodID呢?

这就是sign的作用了,他用于指定要取得的属性/方法的类型。

这里的sign如果指定为"(I)V",则获得的是 void function(int i) 方法的jmethodID;如果指定为"(D)V",则获得的是 void function(double d) 方法的jmethodID

7. sign签名

用来表示要取得的属性/方法的类型

类型 签名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
object L + 用/分隔包的完整类名 + ;
Array [ + 签名 例如,[I、[Ljava/lang/String;
Method (参数1类型签名 参数2类型签名...)返回值类型签名

8. 使用签名获得属性/方法ID的例子(复杂)

import java.util.Date;

public class HelloNative(){
    
    public int property;
    
    public int function(int foo, Date date, int[] arr){
        System.out.println("function");
    }
    
    public native void test();
}

test本地方法的实现

JNIEXPORT void Java_Hello_test(JNIEnv* env, jboject ojb) {
    //因为test不是静态函数,所以传进来的就是调用这个函数的对象
    jclass hello_clazz = env->GetObjectClass(obj);
    jfieldID filedID_prop = env->GetFieldID(hello_clazz, "property", "I");
    jmethodID methodID_func = env->GetMethodID("hello_clazz", "function", "(ILjava/util/Date;[I)I");
    env->CallIntMethod(obj, methodID_func, 0L, NULL, NULL); //invoke
}

取得的property是int类型的,所以在签名中传入"I"

取得function的ID时

1.png

所以在最后得到(ILjava/util/Date;[I)I

9. 使用javap命令来产生签名

-s 表示输出签名信息

-p 通-private,输出包括private访问权限的成员信息

上一篇 下一篇

猜你喜欢

热点阅读