ubuntu14.04下通過JNI使用C++跨語言呼叫java例項
阿新 • • 發佈:2019-02-16
軟體環境:
- 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