Calling Native Code in Java (JNI)

Alex Egg,

You can call native c/c++ code from java using the java native interface (JNI). This will provide a brief introduction and example to get started; and is for my education.

For example we can implement a method to find all the prime number from 0-100 in C and use it w/ our java app.

Our java class should look like this:

public class Primes1
{
  public native int[] findPrimes();

  public static void main(String[] args)
  {
    System.loadLibrary("Primes1");
    Primes1 sample = new Primes1();
    int [] primes = sample.findPrimes();

    System.out.println("findPrimes: " + primes);
  }
}

Now compile this code javac Primes1.java and then run javah Primes1. This generates a header file w/ the findPrimes method signature in - java will use this file to call your native code.

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Primes1 */

#ifndef _Included_Primes1
#define _Included_Primes1
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Primes1
 * Method:    findPrimes
 * Signature: ()[I
 */
JNIEXPORT jintArray JNICALL Java_Primes1_findPrimes
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

Now simple implement your native code per the header file.

#include "Primes1.h"
#include <stdio.h>
#include <jni.h>


JNIEXPORT jintArray JNICALL Java_Primes1_findPrimes
  (JNIEnv *env, jobject obj,  jint num)
  {
    int i;
    int index=0;
    int a[num];

    for(i=0; i<num; i++)
    {
      if(isprime(i))
      {
        a[index]=i;
        index++;
      }

    }

    jintArray arr = (*env)->NewIntArray(env, index);
    (*env)->SetIntArrayRegion(env, arr, 0, index, a);

    return arr;
  }
  
int isprime(int n)
{
  int divisor;

  if (n <= 1)
  {
    return 0;
  }

  for (divisor = 2; divisor <= n-1; divisor++)
  {
    if (n % divisor == 0)
    {
      return 0;
    }
  }

  return 1; // no matches so it's prime
}
  

void main(){}

Now create lib file:

$ gcc -c -I /System/Library/Frameworks/JavaVM.framework/Headers Primes1.c
$ gcc -dynamiclib -o libPrimes1.jnilib Primes1.o -framework JavaVM

Run java app

java Primes1

Speed Comparison

The below benchmarks are the execution times to find all prime numbers between 0 and 300000 using the rudimentary algorithm defined above.

The results are interesting as they are essentially all the same with the JNI example being a second slower than the pure C and pure Java implementations. I am sure this example is contrived and no true demonstration of the usefulness of JNI or the speed advantages of C over Java.

Java JNI

$ time ( java Primes1 )
real	0m25.242s
user	0m24.516s
sys	0m0.139s

Pure Java

$ time ( java PrimeJava )
real	0m24.516s
user	0m24.061s
sys	0m0.197s

Pure C

$ time ./primes
real	0m24.691s
user	0m24.279s
sys	0m0.047s

Comments are welcome below.


Permalink: calling-native-code-in-java-jni

Tags: android, java, c, jni

Last edited by Alex Egg, 2011-06-10 15:54:48
View Revision History