C/C++和Java的交互详解

 更新时间:2016年01月30日 12:07:07   投稿:hebedich  
本文旨在简单的介绍一下如何让java层和C/C++层相互调用,这里主要是使用了JNI技术,并没有深究其原理,只是做了个实现,其目的是为后面的学习打开一扇窗。

安卓中支持c++(NDK)和java(SDK)语言,当使用到c++语言时,c++代码和java如何交互就尤为重要。在下载的NDK包中samples/hello-jni有一个简单的实例可以参考。

java调用C++

新建Android项目,创建如下类:

package com.example.testjni;

public class TextJni {
  // support to c
  static {
    System.loadLibrary("jniinterface");
  }
  public static native int getInt();
  public static native String getString();
}

上面声明了两个native方法,表示getInt和getString的方法实现将在c++(libjniinterface.so)中给出。

在classes目录下运行如下命令,以生成native对应的实现文件。

  javah com.example.testjni.TextJni
  # 注意如果要有Android SDK的类需要指定classpath, 如
  javah -classpath /Users/Richard/dev/android/sdk/platforms/android-19/android.jar:./bin/classes com.togic.gameengine.GFRenderer

生成头文件拷贝出来,创建jni文件夹,并创建出cpp实现文件

com_example_testjni_TextJni.cpp:

#include <stdio.h>
#include <stdlib.h>
#include "com_example_testjni_TextJni.h"

int sum ()
{
  int x,y;
  x = 100 ;
  y = 1000;
  x += y;
  return x;
}

//实现 com_example_textjni_textJNI.h 的方法
JNIEXPORT jint JNICALL Java_com_example_testjni_TextJni_getInt(JNIEnv * env, jclass cls)
{
  return sum();
}

JNIEXPORT jstring JNICALL Java_com_example_testjni_TextJni_getString(JNIEnv * env, jclass cls)
{
  return env->NewStringUTF("HelloNDK!");
}

这里要用到交叉编译,组织c++代码需要用Android.mk。

新建一个Android.mk文件在jni/下

Android.mk:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := jniinterface
LOCAL_SRC_FILES := com_example_testjni_TextJni.cpp

#LOCAL_C_INCLUDES := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)

然后就可以用NDK里的工具:ndk-build来生成动态链接库:libjniinterface.so

生成的库文件就可以被之前的Java文件调用了。

c++ 调用 java

可以在上例中getString方法里利用JNI调用java:

JNIEXPORT jstring JNICALL Java_com_togic_testjni2_TextJni_getString(JNIEnv * env, jclass cls)
{
  jclass TextJni;
  jobject instTextJni;
  jmethodID getCurrInt;

  JNIEnv* jniEnv = env;

  TextJni = jniEnv->FindClass("com/togic/testjni2/TextJni");

  jmethodID construction_id = jniEnv->GetMethodID(TextJni, "init", "()V");
  instTextJni = jniEnv->NewObject(TextJni, construction_id);

  getCurrInt = jniEnv->GetStaticMethodID(TextJni, "getCurrInt","()I");

  // call java static method
  jint jiref = jniEnv->CallStaticIntMethod(TextJni, getCurrInt);

  // clean
  jniEnv->DeleteLocalRef(TextJni);
  jniEnv->DeleteLocalRef(instTextJni);

  std::string strRef = "HelloNDK!" + view->getStaticString();
  return env->NewStringUTF(strRef.c_str());
}

首先值得注意的是jni.h里的函数区分c和c++语言两种接口,对于c++一般如下:

jclass clazz = env->FindClass(classname);

而对于c而言:

jclass clazz = (*env)->FindClass(env, classname);

GetMethodID中第三个参数表示方法签名,可以按如下方法获得:

javap -s 包名.类名   得到方法的签名

附 JNI数据类型转化

jstring 转 char *
const char nativeString = (env)->GetStringUTFChars(env, javaString, 0);

返回指向字符串的 UTF-8 字符数组的指针,该数组在被 ReleaseStringUTFChars() 释放前将一直有效。

(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
char * 转 jstring
jstring jstr = (env)->NewStringUTF(env, char utf)

利用 UTF-8 字符数组构造新 java.lang.String 对象。

其他类型
全选复制放进笔记Java 类型 本地 c 类型 说明
boolean jboolean 无符号,8 位
byte jbyte 无符号,8 位
char jchar 无符号,16 位
short jshort 有符号,16 位
int jint 有符号,32 位
long jlong 有 符号,64 位
float jfloat 32 位
double jdouble 64 位
void void N/A

相关文章

  • SpringBoot基于RabbitMQ实现消息可靠性的方法

    SpringBoot基于RabbitMQ实现消息可靠性的方法

    RabbitMQ 提供了 publisher confirm 机制来避免消息发送到 MQ 过程中丢失,这种机制必须给每个消息指定一个唯一ID,消息发送到MQ以后,会返回一个结果给发送者,表示消息是否处理成功,本文给大家介绍了SpringBoot基于RabbitMQ实现消息可靠性的方法,需要的朋友可以参考下
    2024-04-04
  • SpringBoot集成内存数据库hsqldb的实践

    SpringBoot集成内存数据库hsqldb的实践

    hsqldb只需要添加对应的依赖,然后在配置文件进行配置。不需要安装一个数据库,本文就来介绍一下具体使用,感兴趣的可以了解一下
    2021-09-09
  • Java IO之包装流详解

    Java IO之包装流详解

    这篇文章主要为大家介绍了Java IO之包装流,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • SpringMVC用JsonSerialize日期转换方法

    SpringMVC用JsonSerialize日期转换方法

    下面小编就为大家带来一篇SpringMVC用JsonSerialize日期转换方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起 小编过来看看吧
    2016-11-11
  • Java设计模式之代理模式

    Java设计模式之代理模式

    这篇文章介绍了Java设计模式之代理模式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-09-09
  • Java字节缓存流的构造方法之文件IO流

    Java字节缓存流的构造方法之文件IO流

    这篇文章主要介绍了Java字节缓存流的构造方法之文件IO流,同时也介绍了字符流中的一些相关的内容,并且通过大量的案例供大家理解。最后通过一些经典的案例帮助大家对前面所学的知识做了一个综合的应用,需要的朋友可以参考一下
    2022-04-04
  • springBoot热部署、请求转发与重定向步骤详解

    springBoot热部署、请求转发与重定向步骤详解

    这篇文章主要介绍了springBoot热部署、请求转发与重定向,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • mybatisplus解决驼峰命名映射问题详解

    mybatisplus解决驼峰命名映射问题详解

    这篇文章主要介绍了mybatisplus解决驼峰命名映射问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java通过IO流输出文件目录的实例代码

    Java通过IO流输出文件目录的实例代码

    这篇文章主要介绍了Java通过IO流输出文件目录,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • SpringBoot使用Jackson配置全局时间日期格式

    SpringBoot使用Jackson配置全局时间日期格式

    本文主要介绍了SpringBoot使用Jackson配置全局时间日期格式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05

最新评论