Calling C methods from Java
suggest changeStatic and member methods in Java can be marked as native to indicate that their implementation is to be found in a shared library file. Upon execution of a native method, the JVM looks for a corresponding function in loaded libraries (see Loading native libraries), using a simple name mangling scheme, performs argument conversion and stack setup, then hands over control to native code.
Java code
/*** com/example/jni/JNIJava.java **/ package com.example.jni; public class JNIJava { static { System.loadLibrary("libJNI_CPP"); } // Obviously, native methods may not have a body defined in Java public native void printString(String name); public static native double average(int[] nums); public static void main(final String[] args) { JNIJava jniJava = new JNIJava(); jniJava.printString("Invoked C++ 'printString' from Java"); double d = average(new int[]{1, 2, 3, 4, 7}); System.out.println("Got result from C++ 'average': " + d); } }
C++ code
Header files containing native function declarations should be generated using the javah
tool on target classes. Running the following command at the build directory :
javah -o com_example_jni_JNIJava.hpp com.example.jni.JNIJava
… produces the following header file (comments stripped for brevity) :
// com_example_jni_JNIJava.hpp /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> // The JNI API declarations #ifndef _Included_com_example_jni_JNIJava #define _Included_com_example_jni_JNIJava #ifdef __cplusplus extern "C" { // This is absolutely required if using a C++ compiler #endif JNIEXPORT void JNICALL Java_com_example_jni_JNIJava_printString (JNIEnv *, jobject, jstring); JNIEXPORT jdouble JNICALL Java_com_example_jni_JNIJava_average (JNIEnv *, jclass, jintArray); #ifdef __cplusplus } #endif #endif
Here is an example implementation :
// com_example_jni_JNIJava.cpp #include <iostream> #include "com_example_jni_JNIJava.hpp" using namespace std; JNIEXPORT void JNICALL Java_com_example_jni_JNIJava_printString(JNIEnv *env, jobject jthis, jstring string) { const char *stringInC = env->GetStringUTFChars(string, NULL); if (NULL == stringInC) return; cout << stringInC << endl; env->ReleaseStringUTFChars(string, stringInC); } JNIEXPORT jdouble JNICALL Java_com_example_jni_JNIJava_average(JNIEnv *env, jclass jthis, jintArray intArray) { jint *intArrayInC = env->GetIntArrayElements(intArray, NULL); if (NULL == intArrayInC) return -1; jsize length = env->GetArrayLength(intArray); int sum = 0; for (int i = 0; i < length; i++) { sum += intArrayInC[i]; } env->ReleaseIntArrayElements(intArray, intArrayInC, 0); return (double) sum / length; }
Output
Running the example class above yields the following output :
Invoked C++ ‘printString’ from Java
Got result from C++ ‘average’: 3.4