Original article address:Using JNI in linux to call JAVA classes in C/C ++
Author:Happy Man
Recently, I am working on a C/C ++ program to call java. The Calling method of java here is not exec (/path/to/java ,.....), instead, it calls a specific function in a class file.
The practice is summarized as follows:
1. Install jdk
2. Install gcc (you do not need to install it if it comes with linux)
Java native interface (JNI) is used to dynamically establish java runtime environment.
First, the C/C ++ program contains the header file "jni. h"
# Include <jni. h> is generally in the JAVA_HOME/include directory.
Call the method in jni. h to create the runtime env and then call the java program.
Second, compile
G ++-o testjava. cpp-I $ {JAVA_HOME}/include/linux-L $ {JRE_HOME}/lib/i386/client-ljvm
The above is the general idea. The detailed process is as follows:
######################################## ######################################## #####
1. install and configure the Java environment
My Linux is Redhat Enterprise Linux 5, kernel version 2.6.18
Installing Java in Linux is relatively simple. You can visit the Java download website or the free software library, and select all the operating system types you have installed (Linux, Linux amd64, Solaris, etc ). Once you have chosen to download an object-either a self-decompressed execution file or a self-decompressed RPM file, you can install it. I downloaded the jdk-1_5_0_06-linux-i586.bin:
# Mkdir/usr/local/java # Cd/usr/local/java # Cp/home/soft/jdk-1_5_0_06-linux-i586.bin ./ # Chmod u + x jdk-1_5_0_06-linux-i586.bin #./Jdk-1_5_0_06-linux-i586.bin |
After the jdk1.5.0 _ 06 directory is generated, JDK is installed in/usr/local/Java/jdk1.5.0 _ 06 /. Run the following code to get a test result:
# Cd jdk1.5.0 _ 06/bin [Root @ localhost bin] #./java-version Java version "1.5.0 _ 06" Java (TM) 2 Runtime Environment, Standard Edition (build 1.5.0 _ 06-b05) Java HotSpot (TM) Client VM (build 1.5.0 _ 06-b05, mixed mode, sharing) |
To be able to use Java, you need to set the following environment variables:
JAVA_HOME =/usr/local/java/jdk1.5.0 _ 06 PATH = $ PATH:/usr/local/java/jre1.5.0 _ 05/bin Export JAVA_HOME PATH Export JRE_HOME =/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre Export LD_LIBRARY_PATH = $ LD_LIBRARY_PATH: $ JRE_HOME/lib/i386: $ JRE_HOME/lib/i386/client |
Note the jre_home configuration. If there is no JRE environment on the machine, install JRE. The installation method is similar to installing JDK.
After setting, you can view the variable value.
[Root @ localhost bin] # echo $ java_home
/Usr/local/Java/jdk1.5.0 _ 06
[Root @ localhost bin] # echo $ path
/Usr/Kerberos/sbin:/usr/Kerberos/bin:/usr/local/bin:/usr/bin:/home/zhangp/bin: /usr/lib/JVM/java-1.4.2-gcj-1.4.2.0/JRE/bin:/usr/local/Java/jdk1.5.0 _ 06/bin
2. Compile a simple Java program
Package com. test;
Public class mytest {
Public mytest (){
Super ();
}
Public static int add (int a, int B ){
Return a + B;
}
Public boolean judge (boolean bool ){
Return! Bool;
}
}
Compile the Java program:
# Javac MyTest. java
Generate MyTest after compilation. class, which is placed in the com/test directory of the current directory. when calling the JNI of the C ++ program, the relevant methods will be used to find the class in the com/test directory.
C ++ Program
# Include <stdio. h>
# Include <iostream>
# Include <jni. h>
# Include <stdlib. h>
# Include <assert. h>
Jstring stoJstring (JNIEnv * env, const char * pat)
{
Jclass strClass = env-> FindClass ("java/lang/String ");
JmethodID ctorID = env-> GetMethodID (strClass, "<init>", "([BLjava/lang/String;) V ");
JbyteArray bytes = env-> NewByteArray (strlen (pat ));
Env-> SetByteArrayRegion (bytes, 0, strlen (pat), (jbyte *) pat );
Jstring encoding = env-> NewStringUTF ("UTF-8 ");
Return (jstring) env-> NewObject (strClass, ctorID, bytes, encoding );
}
Char * jstringTostring (JNIEnv * env, jstring jstr)
{
Char * rtn = NULL;
Jclass clsstring = env-> FindClass ("java/lang/String ");
Jstring strencode = env-> newstringutf ("UTF-8 ");
Jmethodid mid = env-> getmethodid (clsstring, "getbytes", "(ljava/lang/string;) [B ");
Jbytearray Barr = (jbytearray) ENV-> callobjectmethod (jstr, mid, strencode );
Jsize Alen = env-> getarraylength (Barr );
Jbyte * Ba = env-> getbytearrayelements (Barr, jni_false );
If (Alen> 0 ){
RTN = (char *) malloc (Alen + 1 );
Memcpy (RTN, Ba, Alen );
RTN [Alen] = 0;
}
Env-> releasebytearrayelements(Barr, Ba, 0 );
Return rtn;
}
Using namespace std;
Int main ()
{
JavaVMOption options [2];
JNIEnv * env;
JavaVM * jvm;
JavaVMInitArgs vm_args;
Long status;
Jclass cls;
JmethodID mid;
Jint square;
Jboolean jnot;
Jobject jobj;
Options [0]. optionString = "-Djava. compiler = NONE ";
Options [1]. optionString = "-Djava. class. path = .";
// Options [2]. optionstring = "-verbose: JNI"; // used for tracking runtime information
Vm_args.version = jni_version_1_4; // JDK version
Vm_args.noptions = 2;
Vm_args.options = options;
Vm_args.ignoreunrecognized = jni_true;
Status = jni_createjavavm (& JVM, (void **) & ENV, & vm_args );
If (status! = Jni_err ){
Printf ("create Java JVM successn ");
CLS = env-> findclass ("com/test/mytest ");// Search for the Ava class here
If (CLS! = 0 ){
Printf ("find java class successn ");
// Constructor
Mid = env-> GetMethodID (cls, "<init>", "() V ");
If (mid! = 0 ){
Jobj = env-> NewObject (cls, mid );
Std: cout <"init OK" <std: endl;
}
// Call the add function
Mid = env-> GetStaticMethodID (cls, "add", "(II) I ");
If (mid! = 0 ){
Square = env-> CallStaticIntMethod (cls, mid, 5 );
Std: cout <square <std: endl;
}
// Call the judge Function
Mid = env-> getmethodid (CLS, "judge", "(z) z ");
If (Mid! = 0 ){
Jnot = env-> callbooleanmethod (jobj, mid, 1 );
If (! Jnot) STD: cout <"Boolean OK" <STD: Endl;
}
}
Else {
Fprintf (stderr, "findclass failedn ");
}
JVM-> destroyjavavm ();
Fprintf (stdout, "Java VM destory. N ");
Return 0;
}
Else {
Printf ("create Java JVM failn ");
Return-1;
}
}
Compile the C ++ Program (premise: the Java environment has been set up, that is, java_home, path, jre_home, LD_LIBRARY_PATH)
[Root @ localhost JNI] # G ++-O testjava. CPP-I $ {java_home}/include/Linux-L $ {jre_home}/lib/i386/client-ljvm
After compilation, you can use LDD testjava to check the correctness of the link library used by the SDK.
Run:
[Root @ localhost JNI] #./testjava
Create Java JVM success
Find Java class success
Init OK
10
Boolean OK
Java VM destory.
Set jre_home and LD_LIBRARY_PATH, and use libjvm under jre_home to compile the C ++ program. so dynamic library (I used the libjvm in the java_home directory I mentioned online at the beginning. so, the following error is returned.
# An Unexpected error has been detected by hotspot virtual machine:
#
#SIGSEGV (0xb) at PC = 0xb6d3dbe3, pid = 14454, tid = 2773482416
#
# Java VM: Java hotspot (TM) server VM (1.5.0 _ 11-b03 Mixed Mode)
.....
------ The end -----
######################################## ######################################## #####