JNI学习

最近需要用到JNI,所以抽时间学习了下,对于我这个N年没用过C/C++的,从没用过VS2005的java码农来说,真不容易,编译个dll都遇到莫名其妙的问题~~

下面就来一步一步开始JNI之路。

一、通过java类得到.h头文件

首先,我们写一个java类,声明几个native方法

package jni.test;

public class JNIWrapper {

    public native void display();

    public native double sum(double x, double y);
    
    public native double divide(double x, double y);
}

然后,依次执行如下命令,依次得到class和.h文件

编译class
...\src>javac jni\test\JNIWrapper.java

生成头文件
...\src>javah jni.test.JNIWrapper

到这里就得到了一个名为“jni_test_JNIWrapper.h”的头文件,其内容如下:

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

#ifndef _Included_jni_test_JNIWrapper
#define _Included_jni_test_JNIWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jni_test_JNIWrapper
 * Method:    display
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jni_test_JNIWrapper_display
  (JNIEnv *, jobject);

/*
 * Class:     jni_test_JNIWrapper
 * Method:    sum
 * Signature: (DD)D
 */
JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_sum
  (JNIEnv *, jobject, jdouble, jdouble);

/*
 * Class:     jni_test_JNIWrapper
 * Method:    divide
 * Signature: (DD)D
 */
JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_divide
  (JNIEnv *, jobject, jdouble, jdouble);

#ifdef __cplusplus
}
#endif
#endif
jni_test_JNIWrapper.h

经过转换之后,方法名、变量类型什么的都变了,不过都挺有规律的:Java_包名+类名(点都换成下划线)_方法名

 

二、创建一个dll工程

首先,在VS2005中,点击新建,出现下图

 

输入Name之后,点击[OK],出现下图:

选择dll,点击finish完成即可创建dll工程

 

三、编写C/C++代码,生成dll

将步骤一种生成的头文件拷贝到工程中“Header Files”目录下,然后新建一个cpp文件,或者直接在默认生成的jnitest.cpp中编码

// jnitest.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "jni_test_JNIWrapper.h"
#include <jni.h> //一定要加上这个

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved
                      )
{
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif



JNIEXPORT void JNICALL Java_jni_test_JNIWrapper_display (JNIEnv *env, jobject obj)
{
    printf("Hello World,JNI!\n");
    return;

}

/*
* Class:     jni_test_JNIWrapper
* Method:    sum
* Signature: (DD)D
*/
JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_sum (JNIEnv *env, jobject obj, jdouble a, jdouble b)
{
    return a + b;
}


JNIEXPORT jdouble JNICALL Java_jni_test_JNIWrapper_divide(JNIEnv *env, jobject obj, jdouble a, jdouble b)
{
    return a/b;
}

然后我们就可以开始编译了。

如果提示找不到“jni.h”,只需要做如下操作即可解决:

在%JAVA_HOME%\include\下找到 jni.h,
在%JAVA_HOME%\include\win32\下找到jni_md.h和jawt_md.h
把他们复制到“Visual Studio目录\VC\include\”下

四、继续完成Java代码调用dll

将步骤三得到的jnitest.dll放到java工程的根目录,注意是java项目的根目录,不是src目录

写个test方法测试下

package jni.test;

public class JNITest {
    static {
        System.loadLibrary("jnitest");
    }
    
    
    public static void main(String[] args) {
        JNIWrapper wrapper = new JNIWrapper();
        wrapper.display();
        System.out.println(wrapper.sum(1.0, 9.9999));
        System.out.println(wrapper.divide(8.4, 2.4));
    }

}

不过,多数情况下,我们会把System.loadLibrary("jnitest")放在JNIWrapper中,即,

package jni.test;

public class JNIWrapper {

    static {
        System.loadLibrary("jnitest");
    }

    public native void display();

    public native double sum(double x, double y);

    public native double divide(double x, double y);
}
JNIWrapper

运行一下,输入结果为

10.9999
3.5000000000000004
Hello World,JNI!

不知道打印“Hello World,JNI!”怎么最后执行~奇怪~

 

到这里,整个JNI调用过程就over了~~

不过还有类型转换什么的,以后再整理了....

 

推荐资料:http://www.iteye.com/topic/304594

 

 

 

 

posted @ 2013-06-07 22:38  yejg1212  阅读(1004)  评论(0编辑  收藏  举报