ubuntu14.04下通过JNI使用C++跨语言调用java实例

参考:https://www.cnblogs.com/andyliu1988/p/6041542.html

https://blog.csdn.net/shensky711/article/details/52806794

软件环境:

  • ubuntu14.04
  • eclipse
  • clion

一、java代码

在eclipse中新建Test工程,package为test,创建Demo类。Demo.java如下。

package test;

public class Demo {
			 //用于演示如何访问静态的基本类型属性  
		    public static int COUNT = 8;  
		    //演示对象型属性  
		    private String msg;  
		    private int[] counts;  
		      
		    public Demo()    {     this("缺省构造函数");      }  
		 
		     //演示如何访问构造器 
		    public Demo(String msg)     {  this.msg = msg;  this.counts = null;    }  	   
		    public String getMessage()     {       return msg;    }  
		   //该方法演示如何访问一个静态方法 
		    public static String getHelloWorld()   {  return "Hello world!";   }  
		  //该方法演示参数的传入传出及中文字符的处理 
		    public String append(String str, int i)   {  return str + i;        }   
		  // 演示数组对象的访问 
		    public int[] getCounts()  {    return counts;     } 
		  //演示如何构造一个数组对象 
		    public void setCounts(int[] counts)   {   this.counts = counts;   }  
		  // 演示异常的捕捉 
		    public void throwExcp()throws IllegalAccessException  
		    {  
		        throw new IllegalAccessException("exception occur.");  
		    }  
}

 

二、C++代码

在clion中新建一个demo1工程,main.cpp如下:

#include <jni.h>
#include <string>
#include <iostream>
#include <memory.h>
using namespace std;

char* jstringToChar(JNIEnv* env, jstring jstr) {
    char* rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("utf-8");//GB2312中文乱码
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen > 0)
    {
        rtn = (char*) malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    env->ReleaseByteArrayElements(barr, ba, 0);
    return rtn;
}
jstring charTojstring(JNIEnv* env, const char* pat) {
    //定义java String类strClass
    jclass strClass = (env)->FindClass("Ljava/lang/String;");
    // 获取String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String
    jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
    //建立byte数组
    jbyteArray bytes = (env)->NewByteArray(strlen(pat));
    // 将char* 转换为byte数组
    (env)->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*) pat);
    // 设置String, 保存语言类型,用于byte数组转换至String时的参数
    jstring encoding = (env)->NewStringUTF("utf-8");
    // 将byte数组转换为java String,并输出
    return (jstring) (env)->NewObject(strClass, ctorID, bytes, encoding);

}

int main() {
    char opt1[] = "-Djava.compiler=NONE"; /** 暂时不知道啥意思,网上抄来的 */
    char opt2[] = "-Djava.class.path=/home/hl/eclipse-workspace/Test/bin";  /** 指定Java类编译后.class文件所在的目录 */
    char opt3[] = "-verbose:NONE";        /** 暂时不知道啥意思,网上抄来的 */

    JavaVMOption options[3];
    options[0].optionString = opt1; options[0].extraInfo = NULL;
    options[1].optionString = opt2; options[1].extraInfo = NULL;
    options[2].optionString = opt3; options[2].extraInfo = NULL;

    JavaVMInitArgs jargv;
    jargv.version = JNI_VERSION_1_6; /** JDK JNI VERSION*/
    jargv.nOptions = 3;
    jargv.options = options;
    jargv.ignoreUnrecognized = JNI_TRUE;

    JavaVM* jvm = NULL;
    JNIEnv* jenv = NULL;
    //创建虚拟机
    jint res = JNI_CreateJavaVM( &jvm, (void**)&jenv, &jargv );
    if ( res < 0 )
        return -1;
    //查找java类
    jclass cls = jenv->FindClass("test/Demo");
    if ( NULL == cls  ) {
        if( jenv->ExceptionOccurred()  )
            jenv->ExceptionDescribe();
        else {
            std::cout << "jc null" << std::endl;
        }
        return 1;
    }
    //调用静态方法  public static String getHelloWorld()  { return "Hello world!"; }
    jmethodID mid = jenv->GetStaticMethodID(cls, "getHelloWorld","()Ljava/lang/String;");
    jstring msg = (jstring)jenv->CallStaticObjectMethod(cls, mid);
    cout<<jstringToChar(jenv, msg)<<endl;

    //调用静态属性  public static int COUNT = 8;
    jfieldID fid = jenv->GetStaticFieldID(cls, "COUNT","I");
    int count = (int)jenv->GetStaticIntField(cls, fid);
    cout<<count<<endl;

    //演示参数的传入传出及中文字符的处理 public String append(String str, int i) { return str + i; }
    jobject obj = jenv->AllocObject(cls);
    jmethodID mid1 = jenv->GetMethodID(cls, "append","(Ljava/lang/String;I)Ljava/lang/String;");
    //构造参数并调用对象的方法
    const char szTest1[] = "苹果";
    jstring arg1 = charTojstring(jenv, szTest1);
    jstring msg1 = (jstring) jenv->CallObjectMethod(obj, mid1, arg1, 12);
    cout<<jstringToChar(jenv, msg1)<<endl;


    //调用构造函数public Demo(String msg) { this.msg = msg; this.counts = null;}
    jmethodID mid2 = jenv->GetMethodID(cls,"<init>","(Ljava/lang/String;)V");
    const char szTest2[] = "电信";
    jstring arg2 = charTojstring(jenv, szTest2);
    jobject demo = jenv->NewObject(cls,mid2,arg2);
    //验证是否构造成功 public String getMessage() { return msg; }
    mid2 = jenv->GetMethodID(cls, "getMessage","()Ljava/lang/String;");
    jstring msg2 = (jstring)jenv->CallObjectMethod(demo, mid2);
    cout<<jstringToChar(jenv, msg2)<<endl;


    //传入传出数组
    //构造数组
    int arrayCpp[] = {1,3,5,7,9};
    jintArray array = jenv->NewIntArray(5);
    jenv->SetIntArrayRegion(array, 0, 5, arrayCpp);
    //传入数组  public void setCounts(int[] counts)  { this.counts = counts; }
    jobject obj1 = jenv->AllocObject(cls);
    jmethodID mid3 = jenv->GetMethodID(cls,"setCounts","([I)V");
    jenv->CallVoidMethod(obj1, mid3, array);
    //获取数组 public int[] getCounts()  {  return counts;  }
    mid3 = jenv->GetMethodID(cls,"getCounts","()[I");
    jintArray msg3 = (jintArray)jenv->CallObjectMethod(obj1, mid3, array);
    int len =jenv->GetArrayLength(msg3);
    jint* elems =jenv-> GetIntArrayElements(msg3, 0);
    for(int i=0; i< len; i++)
    {
        cout<<"ELEMENT "<<i<<" IS "<<elems[i]<<endl;
    }
    jenv->ReleaseIntArrayElements(msg3, elems, 0);


    //异常处理  public void throwExcp()throws IllegalAccessException {  throw new IllegalAccessException("exception occur."); }
    jobject obj2 = jenv->AllocObject(cls);
    jmethodID mid4 = jenv->GetMethodID(cls,"throwExcp","()V");
    jenv->CallVoidMethod(obj2, mid4);
    //获取异常信息
    string exceptionInfo = "";
    jthrowable excp = 0;
    excp = jenv->ExceptionOccurred();
    if(excp)
    {
        jclass cls = jenv->GetObjectClass(excp);
        jenv->ExceptionClear();
        jmethodID mid5 = jenv->GetMethodID(cls, "toString","()Ljava/lang/String;");
        jstring msg = (jstring) jenv->CallObjectMethod(excp, mid5);
        cout<<jstringToChar(jenv, msg)<<endl;
        jenv->ExceptionClear();
    }


    std::cout << "Hi , this is a c++ project!" << std::endl;
    return 0;
}

CMakelists.txt如下:

cmake_minimum_required(VERSION 3.8)
project(demo1)

set(CMAKE_CXX_STANDARD 11)
include_directories("/usr/local/java/jdk-9/include" "/usr/local/java/jdk-9/include/linux")
link_directories(/usr/local/java/jdk-9/lib/server )

set(SOURCE_FILES main.cpp)
add_executable(demo1 ${SOURCE_FILES})

target_link_libraries(
        demo1
        jvm
)

运行结果如下所示:

/home/hl/CLionProjects/demo1/cmake-build-debug/demo1
Hello world!
8
苹果12
电信
ELEMENT 0 IS 1
ELEMENT 1 IS 3
ELEMENT 2 IS 5
ELEMENT 3 IS 7
ELEMENT 4 IS 9
java.lang.IllegalAccessException: exception occur.
Hi , this is a c++ project!

Process finished with exit code 0

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值