缘起

最近对OpenJDK源码产生了很大的兴趣,而其中有较多的native方法,如System.java中的arraycopy方法(第482行)、setOut0方法(第247行)等。Google一下后发现这是Java Native Interface(JNI),便花点时间学习了一下。

何谓JNI?

JNI是Java平台中的一个强大特性。
应用程序可以通过JNI把C/C++代码集成进Java程序中,这样开发者在利用Java平台强大功能的同时,又不必放弃对原有代码的投资。

HelloWorld

闲话少说,先看代码:

新建一个class,名称为Algorithm

public class Algorithm {

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

    public static native void write(String msg);

    public static void main(String[] args) {
        write("Hello, 混合编程!");
    }
}

保存。

打开cmd,cd到\src,执行javah Algorithm(如果你的.java文件在某一package下的话,比如在\mjava\lang\里面,就执行javah mjava.lang.Algorithm),生成Algorithm.h文件,如下:

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

#ifndef _Included_Algorithm
#define _Included_Algorithm
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Algorithm
 * Method:    write
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_Algorithm_write
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

对于Windows下的JDK来说,可以在JDK目录\include\win32\jni_md.h中找到如下定义

#define JNIEXPORT __declspec(dllexport)
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall

其中__declspec用于指定所给定类型的实例的与Microsoft相关的存储方式。
dllexport用来从dll中导出函数,数据或对象,dllimport用来从dll导入函数,数据,或对象。
这相当于定义了dll的接口,提供可被Java使用的C/C++函数,数据,或对象。
__stdcall百度百科
JNIEnvjclassjstring的定义见\include\jni.h,也可以参考jni详解

随后打开VS2012,新建 Win32项目,名称随便:


应用程序类型选择DLL:

alt+F7,点击配置属性-VC++目录,如果你的JDK是64位的话,你的VS2012也应该是64位,此时做如下修改:(32位可以无视)

然后点击包含目录-编辑

点击文件夹图标,把\include\\include\win32\Algorithm.h所在目录加进去。
随后点击常规,把配置类型改为动态库(.dll)

打开<项目名>.cpp,这里<项目名>是你自己输入的名字,输入如下代码:(函数名必须与Algorithm.h中声明的一致)

#include "stdafx.h"
#include "Algorithm.h"

#include <clocale>
#include <cwchar>

JNIEXPORT void JNICALL Java_Algorithm_write(JNIEnv * env, jclass obj, jstring jMsg)
{
    setlocale(LC_ALL, "Chinese-simplified"); // clocale
    wprintf(L"%ls", (wchar_t*)env->GetStringChars(jMsg, NULL));
}

这里setlocale函数用来配置地域化信息,GetStringChars函数将jstring转化成jchar数组并返回jchar*,这里jchar被定义为unsigned short,所以可以转化成wchar_t类型。

F7

在你的项目文件夹中找到<项目名>.dll文件,复制,粘贴到你的工程下(直接在Eclipse中单击工程名然后ctrl+V),并重命名为Hello.dll

回到Eclipse,按下Ctrl+F11,Well done!

More

自定义readLine()方法的实现,见GitHub

Comments

comments powered by Disqus