1 Java 代码
JNI 代码
package com.karashok;
import java.util.UUID;
public class JNIDemo {
/**
* 获取静态方法返回值
*/
public static native String sayHello();
/**
* 获取方法返回值
*/
public native String sayWorld();
/**
* 修改属性 s
*/
public native void setS();
/**
* 修改静态属性 ss
* @return
*/
public native static void setSs();
private String s = "qwer";
private static String ss = "asdf";
public static String getSs() {
return ss;
}
public String getS() {
return s;
}
private long getTime() {
return System.currentTimeMillis();
}
private static String getUUid() {
return UUID.randomUUID().toString();
}
}
main 代码
package com.karashok;
public class Main {
static {
System.load("libDemo.dylib");
}
public static void main(String[] args) {
JNIDemo demo = new JNIDemo();
System.out.println("----- 获取静态方法返回值 -----");
System.out.println("静态方法返回值: " + JNIDemo.sayHello());
System.out.println("----- 获取方法返回值 -----");
System.out.println("方法返回值: " + demo.sayWorld());
System.out.println("----- 修改静态属性 -----");
System.out.println("静态属性修改前: " + JNIDemo.getSs());
JNIDemo.setSs();
System.out.println("静态属性修改后: " + JNIDemo.getSs());
System.out.println("----- 修改属性 -----");
System.out.println("属性修改前: " + demo.getS());
demo.setS();
System.out.println("属性修改后: " + demo.getS());
}
}
2 C 代码
需要将 jni.h
、jni_md.h
两个头文件放到包中。
头文件代码
#include "jni.h"
#include <string.h>
#ifndef DEMO_LIBRARY_H
#define DEMO_LIBRARY_H
/*
* Class: com_karashok_JNIDemo
* Method: sayHello
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_karashok_JNIDemo_sayHello
(JNIEnv *, jclass);
/*
* Class: com_karashok_JNIDemo
* Method: sayWorld
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_karashok_JNIDemo_sayWorld
(JNIEnv *, jobject);
/*
* Class: com_karashok_JNIDemo
* Method: setS
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT void JNICALL Java_com_karashok_JNIDemo_setS
(JNIEnv *, jobject);
/*
* Class: com_karashok_JNIDemo
* Method: setSs
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT void JNICALL Java_com_karashok_JNIDemo_setSs
(JNIEnv *, jclass);
#endif //DEMO_LIBRARY_H
代码
#include "library.h"
JNIEXPORT jstring JNICALL Java_com_karashok_JNIDemo_sayHello(JNIEnv *jniEnv, jclass jcls) {
jmethodID mid = (*jniEnv)->GetStaticMethodID(jniEnv,jcls,"getUUid","()Ljava/lang/String;");
jstring jstr = (*jniEnv)->CallStaticObjectMethod(jniEnv,jcls,mid);
char *str = (*jniEnv)->GetStringUTFChars(jniEnv,jstr,JNI_FALSE);
printf("UUID is: %s\n",str);
return (*jniEnv)->NewStringUTF(jniEnv,"Hello ");
}
JNIEXPORT jstring JNICALL Java_com_karashok_JNIDemo_sayWorld(JNIEnv *jniEnv, jobject jobj) {
jclass jcls = (*jniEnv)->GetObjectClass(jniEnv,jobj);
jmethodID mid = (*jniEnv)->GetMethodID(jniEnv,jcls,"getTime","()J");
jlong jl = (*jniEnv)->CallLongMethod(jniEnv,jobj,mid);
printf("Time is: %ld\n",jl);
return (*jniEnv)->NewStringUTF(jniEnv,"World!\n");
}
JNIEXPORT void JNICALL Java_com_karashok_JNIDemo_setS(JNIEnv *jniEnv, jobject jobj) {
jclass jcls = (*jniEnv)->GetObjectClass(jniEnv,jobj);
jfieldID fid = (*jniEnv)->GetFieldID(jniEnv,jcls,"s","Ljava/lang/String;");
jstring jstr = (*jniEnv)->GetObjectField(jniEnv,jobj,fid);
char *str = (*jniEnv)->GetStringUTFChars(jniEnv,jstr,JNI_FALSE);
char newStr[20] = "Demo ";
strcat(newStr,str);
jstring newjstr = (*jniEnv)->NewStringUTF(jniEnv,newStr);
(*jniEnv)->SetObjectField(jniEnv,jobj,fid,newjstr);
}
JNIEXPORT void JNICALL Java_com_karashok_JNIDemo_setSs(JNIEnv *jniEnv, jclass jcls) {
jfieldID fid = (*jniEnv)->GetStaticFieldID(jniEnv,jcls,"ss","Ljava/lang/String;");
jstring jstr = (*jniEnv)->GetStaticObjectField(jniEnv,jcls,fid);
char *str = (*jniEnv)->GetStringUTFChars(jniEnv,jstr,JNI_FALSE);
char newStr[20] = "Demo ";
strcat(newStr,str);
jstring newjstr = (*jniEnv)->NewStringUTF(jniEnv,newStr);
(*jniEnv)->SetStaticObjectField(jniEnv,jcls,fid,newjstr);
}
3 总结
3.1 获取参数
- 获取 class 对象
- 获取属性的 fieldID
- 获取属性值
- 将属性值转化为 c 的值
3.2 调用方法
- 获取 class 对象
- 获取方法的 methodID
- 调用方法获取返回值
- 将返回值转化为 c 的值
注意: C 调用 Java 方法是不区分权限的,也就是说 public 的属性/方法和 private 的属性/方法是一样的。
获取方法签名:javap -s -p com.karashok.JNIDemo
,一定要尽到相应 src 的根目录下而不是类的目录。