JNI详解

11 篇文章 0 订阅

 Java Native Interface,(JNI)是一个标准的 Java API,它支持将 Java 代码与使用其他编程语言编写的代码相集成。在这里主要就是JavaC++的交互。

    1java调用C++

    首先在java文件中对将要调用的方法做本地声明,关键字为native。且只需要声明,而不需要具体实现。如

    public native void loginSuccessNative(String p_qqId);

    public native static void setStateNative(int i);

 

    然后我们需要在c++文件中实现这些方法,这些方法有特定的格式,我们可以使用javah命令来帮助生成这些方法的声明

    调用javac编译我们的java类,获得class文件,然后javah yourClassName

便可以得到一个.h文件:

 

#include

 

#ifndef _Included_com_test_Hello

#define _Included_com_test_Hello

#ifdef __cplusplus

    extern "C" {

#endif

 

JNIEXPORT void JNICALL Java_com_test_Hello_loginSuccessNative (JNIEnv *, jclass, jstring);

 

JNIEXPORT void JNICALL Java_com_test_setStateNative (JNIEnv *, jclass, jint);

 

#ifdef __cplusplus

}

#endif

#endif

 

    其实只要知道了这个格式,我们也可以自己手动来写。由于java直接回查找cpp里的方法,所以.h文件我们也可以不用声明。

    JNIEXPORT void JNICALL Java_com_test_setStateNative(JNIEnv *, jclass, jint state)

  {

     gameState = state;

 }

  最后我们需要将c++文件,编译成so然后加入java工程,并在java中导入。

    static {

     System.loadLibrary(“test”);

}//系统会自己判断后缀。

 

2:在C++中调用java方法。

C++中调用java会比较麻烦一些,因为需要在C++中获取java的运行环境,并寻找我们要用的类和方法。首先我们需要了解几个概念:

JavaVM:这个代表java的虚拟机。所有的工作都是从获取虚拟机的接口开始的,如何获取这个接口呢?我们之前导入C的组件时调用了:

   System.loadLibrary(“test”);

调用该方法时,java会先调用该组件的JNI_OnLoad()函数.其用途有二: 

一是:告诉java VMC组件使用那一个JNI版本。如果你没有提供JNI_OnLoad()函数,VM会默认使用最老的JNI 1.1版本。由于新版的JNI做了许多扩充,如果需要使用JNI的新版功能,例如JNI 1.4java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM

二是:由于VM执行到System.loadLibrary()函数时,就会立即先呼叫JNI_OnLoad(),所以C组件的开发者可以藉由JNI_OnLoad()来进行C组件内的初期值之设定,也就是获取JavaVM接口。

如:

jint JNI_OnLoad(JavaVM *vm, void *reserved)

{

   JniHelper::setJavaVM(vm);//获取JavaVM接口

   return JNI_VERSION_1_4;//告知java使用什么版本的VM

}

   JNIEnv: 代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用Java对象的方法,获取Java对象的属性等。通过之前获得的JavVM我们可以获取JNIEnv

    static bool getEnv(JNIEnv **env)

    {

       bool bRet = false;

       do

       {

           if (JAVAVM->GetEnv((void**)env, JNI_VERSION_1_4) != JNI_OK)

           {

              LOGD("Failed to get the environment using GetEnv()");

              break;

           }

           if (JAVAVM->AttachCurrentThread(env, 0) < 0)

           {

              LOGD("Failed to get the environment using AttachCurrentThread()");

              break;

           }

           bRet = true;

       } while (0);     

       return bRet;

    }

有了上面的准备,下面我们就可以开始调用java的东西了:

一:获取对象的类id

我们只要知道类的名字就可以通过JNIEnv来获取classid

jclass classID = pEnv->FindClass(className);

二:获取要调用的方法id,包括静态和普通方法。

    jmethodID methodID = pEnv->GetStaticMethodID(classID, methodName, paramCode);

    jmethodID methodID = pEnv->GetMethodID(classID,methodName, paramCode);

    这其中的最后一个参数代表方法的参数信息,因为java支持多态,只有完整的参数信息才可以找到唯一的方法。这个参数有着特定的格式,见附录。 

 

三:调用方法,同样包括静态和普通。

    pEnv ->CallStatic***Method(classID,methodID);

         pEnv ->Call***Method(classID,methodID);

  不同的返回参数,调用不同的方法,如CallBooleanMethodCallIntMethodCallObjectMethodCallStaticIntMethod等等。

 

 

附:函数属性签名规则:

    GetMethodID最后一个参数是签名字符串,用来标示java函数和成员的唯一性。因为java中存在重载函数,所以一个函数名不足以唯一指定一个函数,这时候就需要签名字符串来指定函数的参数列表和返回值类型了。
函数签名是一个字符串:"(M)N",括号中的内容是函数的参数类型,括号后面表示函数的返回值。

    具体的每一个字符的对应关系如下
字符  Java类型     C类型
  void       void
  jboolean    boolean
  jint        int
  jlong      long
  jdouble     double
  jfloat       float
  jbyte        byte
  jchar        char
  jshort       short

数组则以”["开始,用两个字符表示
[I   jintArray    int[]
[F   jfloatArray  float[]
[B   jbyteArray   byte[]
[C   jcharArray   char[]
[S   jshortArray  short[]
[D   jdoubleArray double[]
[J   jlongArray   long[]
[Z  jbooleanArray boolean[]


   
 如果Java函数的参数是class,则以”L”开头,以”;”结尾,中间是用”/” 隔开的包及类名。而其对应的C函数名的参数则为jobject
   
 一个例外是String类,其对应的类为jstring
    Ljava/lang/String; String jstring
    Ljava/net/Socket; Socket jobject

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值