本例环境:Macos。
JDK的环境变量当然是必须首先可用的,只要终端执行 java 能运行即可。
首先,有个java类MyTest.java文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// 没有包 public class MyTest { static{ // 可能出现的错误: // java.lang.UnsatisfiedLinkError: no MyTest in java.library.path: // 此时可以指定java.library.path: // java -Djava.library.path=dylib文件绝对路径 MyTest // 查看第三方库path:System.getProperty("java.library.path"); System.loadLibrary("MyTest"); // 这个"MyTest"库对应的dylib文件名是 “libMyTest.dylib”,前缀“lib” } public String name = "张三"; public static void main(String[] args) { System.out.println("Hello JNI"); MyTest test = new MyTest(); test.changeJavasNameField(); // ----------调用本地方法 System.out.println("Java中的值:" + test.name); } public native void changeJavasNameField(); // native方法,无参,无返回值 public native void printLog(String log); // native方法,有参,无返回值 public static native String GetJNIString(); // native方法,静态的,无参,有返回值 // 根据本java类中的本地方法,生成h文件: // 在当前类所在的路径下执行: // javac -encoding UTF-8 -h . MyTest.java // 当前目录下得到 MyTest.h,重命名为MyTest.cc,实现代码 // 然后 gcc -dynamiclib -lstdc++ -o libMyTest.dylib MyTest.cc 编译 } |
然后,在这个java文件所在的路径下,使用 javac 生成 h 文件。
1 2 3 |
javac -encoding UTF-8 -h . MyTest.java |
然后,修改这个h文件为c++的源码文件MyTest.cc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include <iostream> #include <string> #include "jni.h" // ------- 注意本例手动的,这里是双引号引入。如果使用IDE可能默认是尖括号 using namespace std; #ifndef _Included_MyTest #define _Included_MyTest #ifdef __cplusplus extern "C" { #endif /* * JNIEnv * env 上下文 * Object: obj,定义此方法的java类MyTest的实例 * Method: java中函数名:changeJavasNameField * Signature: 无参,无返回值:()V */ JNIEXPORT void JNICALL Java_MyTest_changeJavasNameField(JNIEnv * env, jobject obj){ jclass clazz = env->GetObjectClass(obj); // 拿到java对象的类 jfieldID filedID = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); // 拿到java对象的属性ID jobject nameObj = env->GetObjectField(obj, filedID); // 拿到属性 jstring name = (jstring)nameObj; // 拿到java的String型属性 char* str = (char*)(env->GetStringUTFChars(name, 0)); // 属性的初始值 cout << "java中的值" << str << endl; jstring new_name = env->NewStringUTF("李四"); env->SetObjectField(obj, filedID, new_name); // 更新java的属性 cout << "从jni设置java变量结束" << endl; } /* * JNIEnv * env 上下文 * Object: obj,定义此方法的java类MyTest的实例 * Method: java中函数名:printLog * Signature: 参数为String,无返回值:(Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_MyTest_printLog(JNIEnv * env, jobject obj, jstring log){ } /* * JNIEnv * env 上下文 * Class: clazz, 定义此【静态方法】的java类:MyTest.class * Method: java中函数名:GetJNIString * Signature: 无参,返回值类型为String:()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_MyTest_GetJNIString(JNIEnv * env, jclass clazz) { return NULL; } #ifdef __cplusplus } #endif #endif // 可能出现的错误: // Undefined symbols for architecture x86_64 // 编译时添加参数 -dynamiclib -lstdc++: // gcc -dynamiclib -lstdc++ -o libMyTest.dylib MyTest.cc // 得到 libMyTest.dylib ,前缀lib // nm libMyTest.dylib | grep MyTest 可以看到自定义的函数 // // 如果java调用时出现错误: // A fatal error has been detected by the Java Runtime Environment: // 啥啥啥xxxx。。。 // Exception <a 'java/lang/NoSuchFieldError' // 啥啥啥xxxx。。。 // 很可能引用类型的参数错误了,如: // GetFieldID(clazz, "name", "Ljava/lang/String;");写成了GetFieldID(clazz, "name", "Ljava/lang/String"); // 少了一个分号 |
编译这个cc文件:
1 2 3 |
gcc -dynamiclib -lstdc++ -o libMyTest.dylib MyTest.cc |
得到 libMyTest.dylib ,在java中加载时,忽略“lib”这3个字母。
还要准备 jni.h 文件和 jni_md.h 文件,可以从 jdk目录 /include/ 下找到,或者 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/ 下,复制到 MyTest.java文件目录。
最后,执行java测试:
1 2 3 4 |
javac MyTest.java java MyTest |
$ java MyTest
Hello JNI
java中的值张三
从jni设置java变量结束
Java中的值:李四
$
- end
声明
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/3695.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设