1、定義native方法並加載動態鏈接庫:
public class HelloJni extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } public native String stringFromJNI(); public native String unimplementedStringFromJNI(); static { System.loadLibrary("hello-jni"); } }
2、實現native方法:
#include <string.h> #include <jni.h> jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); //in c
return env->NewStringUTF("Hello from JNI !"); //in c++
}
若要定義靜態方法:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI (JNIEnv * env, jclass clazz);
頭文件可以用javah工具生成:
進入命令行,切換到項目的bin目錄下的classes下面,執行 javah -classpath . -jni 包.類名。
或者:cd 到src目錄中,執行 javah 包.類名
3、數據
原始數據類型:
引用數據類型:
4、字符竄的操作:
1)新建字符串:
jstring javaString;
javaString = (*env)->NewStringUTF(env, "Hello World!");
2)把java string轉換成c string
const jbyte* str; jboolean isCopy; str = (*env)->GetStringUTFChars(env, javaString, &isCopy); if (0 != str) { printf("Java string: %s", str); if (JNI_TRUE == isCopy) { printf("C string is a copy of the Java string."); } else { printf("C string points to actual string."); } (*env)->ReleaseStringUTFChars(env, javaString, str);
5、數組的操作:
1)新建java數組:
jintArray javaArray; javaArray = (*env)->NewIntArray(env, 10); if (0 != javaArray) { /* You can now use the array. */ }
2)獲取數組的值:
jint nativeArray[10];
//將java array 復制到 c array (*env)->GetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
//將 c array 還原城 java array
(*env)->SetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
獲取數組指針:
jint* nativeDirectArray; jboolean isCopy; nativeDirectArray = (*env)->GetIntArrayElements(env, javaArray, &isCopy);
//...
(*env)->ReleaseIntArrayElements(env, javaArray, nativeDirectArray, 0);
6、C\C++獲取java成員變量
public class JavaClass { /** Instance field */ private String instanceField = "Instance Field"; /** Static field */ private static String staticField = "Static Field"; ... }
1)獲取Field ID
jclass clazz;
clazz = (*env)->GetObjectClass(env, instance);
jfieldID instanceFieldId; instanceFieldId = (*env)->GetFieldID(env, clazz, "instanceField", "Ljava/lang/String;");
jfieldID staticFieldId; staticFieldId = (*env)->GetStaticFieldID(env, clazz, "staticField", "Ljava/lang/String;");
2)獲取Static Field
jstring staticField;
staticField = (*env)->GetStaticObjectField(env, clazz, staticFieldId);
7、C\C++調用java函數
public class JavaClass { /** * Instance method. */ private String instanceMethod() { return "Instance Method"; } /** * Static method. */ private static String staticMethod() { return "Static Method"; } ... }
1)獲取Method ID:
成員函數:
jmethodID instanceMethodId; instanceMethodId = (*env)->GetMethodID(env, clazz, "instanceMethod", "()Ljava/lang/String;");
靜態函數:
jmethodID staticMethodId; staticMethodId = (*env)->GetStaticMethodID(env, clazz, "staticMethod", "()Ljava/lang/String;");
2)調用:
jstring instanceMethodResult; instanceMethodResult = (*env)->CallStringMethod(env, instance, instanceMethodId);
變量和函數的描述符:
javap工具可以提取從編譯過的class files 中提取這些描述符:
javap –classpath bin/classes –p –s com.example.hellojni.HelloJni
8、處理異常:
public class JavaClass { /** * Throwing method. */ private void throwingMethod() throws NullPointerException { throw new NullPointerException("Null pointer"); } /** * Access methods native method. */ private native void accessMethods(); }
jthrowable ex; ... (*env)->CallVoidMethod(env, instance, throwingMethodId); ex = (*env)->ExceptionOccurred(env); if (0 != ex) { (*env)->ExceptionClear(env); /* Exception handler. */ }
從c\c++拋異常:
jclass clazz; ... clazz = (*env)->FindClass(env, "java/lang/NullPointerException"); if (0 ! = clazz) { (*env)->ThrowNew(env, clazz, "Exception message."); }
9、本地和全局變量:
1)本地變量在函數結束時自動釋放內存:
jclass clazz; clazz = (*env)->FindClass(env, "java/lang/String");
2)新建全局變量:
jclass localClazz; jclass globalClazz; ... localClazz = (*env)->FindClass(env, "java/lang/String"); globalClazz = (*env)->NewGlobalRef(env, localClazz); ... (*env)->DeleteLocalRef(env, localClazz);
3)釋放全局變量:
(*env)->DeleteGlobalRef(env, globalClazz);
4)弱全局引用:
弱全局引用可以被內存自動回收:
jclass weakGlobalClazz; weakGlobalClazz = (*env)->NewWeakGlobalRef(env, localClazz); if (JNI_FALSE == (*env)->IsSameObject(env, weakGlobalClazz, NULL)) { /* Object is still live and can be used. */ } else { /* Object is garbage collected and cannot be used. */ } (*env)->DeleteWeakGlobalRef(env, weakGlobalClazz);
10、線程:
synchronized(obj) { /* Synchronized thread-safe code block. */ }
if (JNI_OK == (*env)->MonitorEnter(env, obj)) { /* Error handling. */ } /* Synchronized thread-safe code block. */ if (JNI_OK == (*env)->MonitorExit(env, obj)) { /* Error handling. */ }
native線程不能和java直接通信,必須先綁定到javaVM
JavaVM* cachedJvm; ... JNIEnv* env; ... /* Attach the current thread to virtual machine. */ (*cachedJvm)->AttachCurrentThread(cachedJvm, &env, NULL); /* Thread can communicate with the Java application using the JNIEnv interface. */ /* Detach the current thread from virtual machine. */ (*cachedJvm)->DetachCurrentThread(cachedJvm);