欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

JNI入门——hello jni,jni入门hello

来源: javaer 分享于  点击 19467 次 点评:128

JNI入门——hello jni,jni入门hello


概念

JNI(Java Native Interface,Java本地接口),实现了Java和其他语言的交互(主要是C/C++)。使用java与本地已编译的其他代码交互,通常会丧失平台可移植性,应尽量避免,但在某些情况是有必要使用的,如为了使用一些旧的第三方库,与硬件、操作系统进行交互,或者为了提高程序的性能。

使用原因:
1. 功能:想直接使用C/C++编写好的功能,如与底层进行交互。
2. 效率:在一些复杂算法的处理上,使用C语言处理比起java高效很多
3. 安全:java是半解释型语言,很容易被反汇编后拿到源代码,因此可以在重要的交互功能使用C语言代替。

使用注意:
应该让native方法集中在少数几个类当中,以降低Java和其他语言之间的耦合。

入门使用

下面用JNI实现一个功能:Java代码将参数name传给C,C返回”hello,name”给Java进行输出。主要步骤是:

1.编写HelloJNI.java

代码如下,留意包名:

package com.kwws.demo.jni;

public class HelloJNI {
    //用native关键字声明一个本地方法,将由C/C++进行实现
    public native String getHello(String name);

    //静态方法载入JNI_Hello库,不带后缀
    static {
        System.loadLibrary("JNI_Hello");
    }

    public static void main(String[] args) {
        //JNI调用
        String msg = new HelloJNI().getHello("jni");
        System.out.println(msg);
    }
}

2.编译HelloJNI.java

使用javac命令将.java编译为.class:

E:\JavaProject\HelloJNI\src\com\kwws\demo\jni>javac HelloJNI.java

当然,使用Eclipse编写的.java会自动编译,可以在以下路径找到.class:

\HelloJNI\bin\com\kwws\demo\jni\HelloJNI.class

3.生成JNI接口声明HelloJNI.h

使用javah命令将.java(.class?)中的本地方法抽象为接口,命名为.h。
定位到com.kwws.demo.jni.HelloJNI.java的上级目录\src,连同包名进行javah命令:

//定位到顶级包名所在目录;带完整包路径、不带.java后缀
E:\JavaProject\HelloJNI\src>javah com.kwws.demo.jni.HelloJNI

P.S.
实践中发现,javah命令好像对是.java代码进行的处理,不编译为.class也可得到.h文件。因此,步骤2可以跳过?

完成后,可在\src下看到生成的.h文件:

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

#ifndef _Included_com_kwws_demo_jni_HelloJNI
#define _Included_com_kwws_demo_jni_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_kwws_demo_jni_HelloJNI
 * Method:    getHello
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_kwws_demo_jni_HelloJNI_getHello
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

该文件中的方法Java_com_kwws_demo_jni_HelloJNI_getHello就是.java中的对应方法在JNI中的调用接口,按“Java_包路径类名方法名”命名。
参数部分,第三个参数jstring对应Java中的唯一的string类型参数,而第1、2个参数是JNI交互使用的桥梁,应该是Java对象在内存中的指针。

4.用C/C++实现HelloJNI.h中的接口方法

编写C/C++,包含<jni.h>(其中包含对JNIEnv、jobject等JNI对象的定义),以及自己的com_kwws_demo_jni_HelloJNI.h(包含调用接口)。
其中对jstring参数的处理就省略掉了,直接返回新的字符串。

//JNI_Hello.c
#include <jni.h>
#include "com_kwws_demo_jni_HelloJNI.h"

JNIEXPORT jstring JNICALL 
Java_com_kwws_demo_jni_HelloJNI_getHello
  (JNIEnv *env, jobject obj, jstring name) { //需自行加上参数名
    return (*env)->NewStringUTF(env, "hello from jni.");
}

P.S.
在C/C++中,对 JNIEnv *env 的使用方式不同:

// C: (*env)->
// C++: env->

5. 编译JNI_Hello.c为JNI_Hello.dll给Java调用

因为我好久没写C/C++的代码了,电脑上压根就没有C/C++的编译工具。主要是在Android学习中涉及了JNI的使用,而Android的NDK自带了C/C++的编译器。在Android的背景下,NDK编译生成.so文件供给Java层调用。
JNI独立使用时,编译C/C++代码成什么形式我不太确定(没特地去写),因此先留个问号,之后如果有遇到实践的机会再补充。
编译C/C++为动态链接库DLL,以及Java层的调用,可以参考:JNI的使用:HelloWorld

Eclipse集成JNI操作

前文中对JNI的操作都使用cmd命令,显然在工作中十分不便,好在可以将这些操作都集成到Eclipse中的按钮,一键完成任务。
参考:Eclipse集成JNI与AndroidNDK操作

参考

相关文章

    暂无相关文章
相关栏目:

用户点评