Java与C语言混合编程

来源:互联网 发布:大宗师 外网端口 编辑:程序博客网 时间:2024/05/16 07:12
Java提供了native关键字,该关键字用来声明本机代码方法。

声明一个本机方法,在该方法之前用native修饰符,但是不要定义任何方法体。例如:

public native int meth() ;
很多本机方法是用C写的。把C代码结合到 Java 程序中的机制是调用。
首先输入java短程序,使用了一个名为square的native方法:
 /*程序名为Main.java */public class Main {        public native int square(int i);        public static void main(String[] args) {                System.loadLibrary("Main");                System.out.println(new Main().square(2));        }}
注意square(int i )方法声明为native且不含方法体。本地执行方法square( )的动态链接库由loadLibrary( )方法加载。loadLibrary( )方法是System类的组成单元。它的一般形式为:

static void loadLibrary(String filename)
这里,filename是指定保存该库文件名的字符串。在Windows环境下,该文件的扩展名为.DLL;在Linux下,该文件扩展名为.so。


写完程序后,编译它生成Main.class。然后,你必须用javah生成一个文件:Main.h(javah包含在JDK中)。在执行square( )时你要包含Main.h。
为生成Main.h,用下面的命令:

javah -jni Main
生成Main.h文件如下:

 /*  DO NOT EDIT THIS FILE - it is machine generated  */ #include <jni.h>/*  Header for class Main  */#ifndef _Included_Main#define _Included_Main#ifdef __cplusplusextern "C" {#endifJNIEXPORT jint JNICALL Java_Main_square        (JNIEnv *, jobject, jint);#ifdef __cplusplus}#endif#endif
请特别注意下面一行,该行定义了所要创建的square( )函数的原型:

JNIEXPORT jint JNICALL ;
     注意函数的名称是Java_Main_square( )。调用本机函数你必须用这样的名字。也就是说,不是生成一个名为square( )的C函数,而是创建一个名为函数。加入前缀Main是因为它把square( )方法作为Main类的一部分。记住,其他类可以定义它们自己的与Main定义的完全不同的本地square( )方法。前缀中包括类名的方法解决了区分不同版本的问题。作为一个常规方法,给本机函数取名,前缀中必须包括声明它们的类名。


生成了必备的头文件后,可以编写square( )执行文件并把它存在一个名为Main.c的文件中:

#include  <jni.h>#include  "Main.h"JNIEXPORT jint JNICALL Java_Main_square(        JNIEnv *env, jobject obj, jint i) {        return i * i  ;}
上面我们讲到,用javac编译成成.class文件,用javah -jni编译成成.h文件,接下来,我们要编译.c的代码:

gcc   -shared   -fpic   -o   libMain.so   -I${JAVA_HOME}/include   -I${JAVA_HOME}/include/linux   Main.c
这生成了linux下的动态库so。
运行方法:

java   -Djava.library.path=.   Main
这里需要注意:libMain.so文件名固定,与 System.loadLibrary("Main")中的Main保持一致。
命名:Main--->lib+Main+.so--->libMain.so



给出另外一个函数中没有传递变量的例子,实现写好.c文件:
NativeDemo.java文件如下:

 public class NativeDemo {         int i;         public static void main(String args[]) {                  NativeDemo ob = new NativeDemo();                  ob.i = 10;                  System.out.println("This is ob.i before the native method:" + ob.i);                  ob.test(); // call a native method                  System.out.println("This is ob.i after the native method:" + ob.i);                   new NativeDemo().test2(31);         }         // declare native method         public native void test() ;         public native void test2(int a) ;         // load DLL that contains static method         static {                   System.loadLibrary("NativeDemo");         }}

NavtiveDemo.h文件如下:

 /* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class NativeDemo */#ifndef _Included_NativeDemo#define _Included_NativeDemo#ifdef __cplusplusextern " C " {#endif/* * Class:     NativeDemo * Method:    test * Signature: ()V */JNIEXPORT void JNICALL Java_NativeDemo_test         (JNIEnv *, jobject);/* * Class:     NativeDemo * Method:    test2 * Signature: (I)V */JNIEXPORT void JNICALL Java_NativeDemo_test2         (JNIEnv *, jobject, jint);#ifdef __cplusplus}#endif#endif

NativeDemo.c文件为:

#include <jni.h>#include "NativeDemo.h"#include <stdio.h>JNIEXPORT void JNICALL Java_NativeDemo_test(JNIEnv *env, jobject obj){        jclass cls;        jfieldID fid;        jint i;        printf("Starting the native method.\n");        cls = (*env)->GetObjectClass(env, obj);        fid = (*env)->GetFieldID(env, cls, "i", "I");        if(fid == 0) {                 printf("Could not get field id.\n");                 return;         }        i = (*env)->GetIntField(env, obj, fid);        printf("i = %d\n", i);        (*env)->SetIntField(env, obj, fid, 2*i);        printf("Ending the native method.\n");}JNIEXPORT void JNICALL Java_NativeDemo_test2(JNIEnv *env, jobject obj, jint i){        printf("i = %d\n",i);}


编译的shell文件:
javac   NativeDemo.javajavah   -jni   NativeDemogcc  -shared  -fpic  -o  libNativeDemo.so   -I${JAVA_HOME}/include  -I${JAVA_HOME}/include/linux   NativeDemo.cjava   -Djava.library.path=.   NativeDemorm   *~   *class   *so


原创粉丝点击