您当前的位置:首页 > 计算机 > 编程开发 > C语言

Java和C语言混合编译

时间:03-07来源:作者:点击数:

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 __cplusplus
extern "C" {
#endif
JNIEXPORT 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 __cplusplus
extern " 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.java
javah   -jni   NativeDemo
gcc  -shared  -fpic  -o  libNativeDemo.so   -I${JAVA_HOME}/include  -I${JAVA_HOME}/include/linux   NativeDemo.c
java   -Djava.library.path=.   NativeDemo
rm   *~   *class   *so
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门