首先在同一路徑下創建兩個文件夾:c和java,分別用來保存c代碼和java代碼。
1.編寫java代碼(Hello.java)
package com.test.base64;
public class Hello{
public String hello(String name){
return "hello,"+name;
}
}
2.編譯java代碼
javac Hello.java -----> Hello.class
3.編寫C代碼(test.c)
在C/C++中調用Java的方法一般分爲五個步驟:初始化虛擬機、獲取類、獲取類的方法、創建類對象、調用方法和退出虛擬機。
#include <stdio.h>
#include "jni.h"
#include <string.h>
/**
* 初始化jvm
*/
JNIEnv* create_vm() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=../java";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, &env, &args);
return env;
}
/**
* 根據全限定類名來獲取類的定義
*/
jclass create_class(JNIEnv* env,char *className){
jclass cls = (*env)->FindClass(env,className);
if(cls == 0){
printf("class-[%s] find error\n",className);
return;
}
return cls;
}
/**
* 通過無參構造函數來獲取對應類的實例
*/
jobject getInstance(JNIEnv* env, jclass obj_class)
{
jmethodID construction_id = (*env)->GetMethodID(env,obj_class, "<init>", "()V");
jobject obj = (*env)->NewObject(env,obj_class, construction_id);
if(obj == 0){
printf("java class instance failed\n");
return;
}
return obj;
}
/**
* 根據類\方法名\返回值\參數獲取類中對應的方法定義
*/
jmethodID get_method(JNIEnv* env,jclass cls,char *methodName,char *key){
jmethodID mid = (*env)->GetMethodID(env,cls,methodName,key);
if(mid == 0){
printf("method-%s is not found\n",methodName);
return;
}
return mid;
}
/**
* 轉換c中的字符串爲java.lang.String,這個方法是從網上找到的,感謝原作者<a href="http://home.cnblogs.com/u/liangwind/">天末涼風</a>
*/
jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = (*env)->FindClass(env,"Ljava/lang/String;");
jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env,strlen(pat));
(*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = (*env)->NewStringUTF(env,"utf-8");
return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);
}
void invoke(){
JNIEnv* env = create_vm(); //初始化java虛擬機
jclass cls = create_class(env,"com/test/base64/Hello");//根據類名找到對應的類
jobject obj = getInstance(env,cls);//然後根據類獲取對應的實例
jmethodID hello = get_method(env,cls,"hello","(Ljava/lang/String;)Ljava/lang/String;");//根據類\方法名和簽名獲取到對應的方法
jstring name_str = (*env)->CallObjectMethod(env,obj,hello,stoJstring(env,"xxx"));//傳入參數調用方法
const char* pname = (*env)->GetStringUTFChars(env,name_str, NULL);//將返回的java字符串轉換爲c字符串
printf("the result is:%s\n",pname);//打印出調用的結果
}
int main(int argc, char **argv) {
invoke();
}
4.編譯C代碼
gcc -o test test.c -L/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server -ljvm //根據自己的情況鏈接libjvm.so庫
test.c ----> test
5 執行
./test