• JNI查漏补缺(3)JNI调用java层


    目录

    一、JNI调用java层基本方法

    二、JNI调用java层步骤

    1.关键函数和基本步骤

    2.HelloWorld示例

    总结


    一、JNI调用java层基本方法

    JNI层调用java层,主要是通过反射机制找到class的成员变量和成员函数进行调用。

    二、JNI调用java层步骤

    1.关键函数和基本步骤

    1. //JNIEnv: JNIEnv是一份JNI环境,提供了大部分jni的接口,但是它是一个与线程相关的变量,不能保存为全局变量,需要时再从传入的env中调用
    2. //JavaVM;JavaVM是一份java虚拟机的实例,通过JNI_ONload函数传入,由于进程内共享,所以传入后即可保存为全局变量。JavaVM可以获取当前线程的env,调用方法为:JavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)
    3. /*
    4. * Class: HelloWorld
    5. * Method: sayhello
    6. * Signature: ()V
    7. */
    8. JNIEXPORT void JNICALL Dynamic_Java_HelloWorld_sayhello
    9. (JNIEnv *env, jobject thiz)
    10. {
    11. printf("jni say hello world\n");
    12. //GetObjectClass通过传入类对象参数,用于获取class对象,获取class对象的用处时用于反射机制找到成员变量或者成员函数
    13. jclass HelloWorldClazz=env->GetObjectClass(thiz);
    14. //GetFieldID通过传入class对象和成员变量变量名和变量类型,从而利用反射机制获取了得到成员变量的方法,不过限制时智能获取声明为public的成员变量或者成员方法。
    15. jfieldID num_id=env->GetFieldID(HelloWorldClazz,"num","I");
    16. //GetIntField通过反射返回一个实例的一个成员变量
    17. int num=env->GetIntField(thiz,num_id);
    18. printf("jni get num :[%d]\n",num);
    19. num = 886;
    20. printf("jni set num :[%d]\n",num);
    21. //SetIntField通过反射设置一个实例的一个成员变量
    22. env->SetIntField(thiz,num_id,num);
    23. //GetMethodID通过传入class对象和成员函数函数名和函数类型,
    24. jmethodID saybyebye_id=env->GetMethodID(HelloWorldClazz,"saybyebye","()V");
    25. printf("jni call byebye\n");
    26. //CallVoidMethod调用一个实例的无返回值方法
    27. env->CallVoidMethod(thiz,saybyebye_id);
    28. //一般情况new的变量需要delete
    29. env->DeleteLocalRef(HelloWorldClazz);
    30. }

    2.HelloWorld示例

    修改HelloWorld.cpp

    1. #include <jni.h>
    2. #include <stdio.h>
    3. #include "HelloWorld.h"
    4. #ifdef __cplusplus
    5. extern "C" {
    6. #endif
    7. /*
    8. * Class: HelloWorld
    9. * Method: sayhello
    10. * Signature: ()V
    11. */
    12. JNIEXPORT void JNICALL Dynamic_Java_HelloWorld_sayhello
    13. (JNIEnv *env, jobject thiz)
    14. {
    15. printf("jni say hello world\n");
    16. jclass HelloWorldClazz=env->GetObjectClass(thiz);
    17. jfieldID num_id=env->GetFieldID(HelloWorldClazz,"num","I");
    18. int num=env->GetIntField(thiz,num_id);
    19. printf("jni get num :[%d]\n",num);
    20. num = 886;
    21. printf("jni set num :[%d]\n",num);
    22. env->SetIntField(thiz,num_id,num);
    23. jmethodID saybyebye_id=env->GetMethodID(HelloWorldClazz,"saybyebye","()V");
    24. printf("jni call byebye\n");
    25. env->CallVoidMethod(thiz,saybyebye_id);
    26. env->DeleteLocalRef(HelloWorldClazz);
    27. }
    28. static JNINativeMethod gMethods[]=
    29. {
    30. {"sayhello","()V",(void*)Dynamic_Java_HelloWorld_sayhello}
    31. };
    32. jint JNI_OnLoad(JavaVM* vm,void* reserved)
    33. {
    34. JNIEnv *env=NULL;
    35. jint result =-1;
    36. if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK)
    37. {
    38. return -1;
    39. }
    40. char className[20]={"HelloWorld"};
    41. jclass clazz=env->FindClass((const char*)className);
    42. if(env->RegisterNatives(clazz,gMethods,1)<0)
    43. {
    44. return -1;
    45. }
    46. result=JNI_VERSION_1_4;
    47. printf("JNI_ONload\n");
    48. return result;
    49. }
    50. #ifdef __cplusplus
    51. }
    52. #endif

    修改HelloWorld.java

    1. public class HelloWorld
    2. {
    3. static
    4. {
    5. System.loadLibrary("HelloWorld");
    6. }
    7. public int num = 0;
    8. public void saybyebye()
    9. {
    10. System.out.println("java saybyebye,num="+num);
    11. }
    12. public native void sayhello();
    13. public static void main(String[] args)
    14. {
    15. HelloWorld hw = new HelloWorld();
    16. System.out.println("call jni sayhello");
    17. hw.sayhello();
    18. }
    19. }

    编译

    1. #编译java类
    2. javac HelloWorld.java
    3. #编译jni so库
    4. gcc HelloWorld.cpp --shared -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC

    运行HelloWorld

    1. java HelloWorld
    2. #JNI_ONload
    3. #java call jni sayhello
    4. #jni say hello world
    5. #jni get num:[0]
    6. #jni set num:[886]
    7. #jni call byebye
    8. #java say byebye,num=886

    可以看到jni层调用了java层HelloWorld类的saybyebye的成员函数,并且成员变量也发生了改变


    总结

    jni调用java层是要反射机制调用。

  • 相关阅读:
    程序人生:去了字节跳动,才知道年薪40W的测试有这么多?
    网络安全(黑客)自学
    新款WDS型单轭双调电磁铁
    Koa.js搭建简单服务器,连接数据库
    java方法是什么?
    CH06_第一组重构(上)
    MacOS怎么安装Nacos(附带:Windows系统)
    掌握Java核心知识,轻松应对面试挑战!
    sqlserver的字符集配置
    Spring Boot 整合多数据源,这才叫优雅
  • 原文地址:https://blog.csdn.net/xiaoshixiu/article/details/133923106