JNI入门——hello jni

12 篇文章 0 订阅

概念

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. 编写带有native关键字的方法的java类:HelloJNI.java
  2. (好像可省)编译HelloJNI.java -> HelloJNI.class(javac命令)
  3. 生成HelloJNI.class类的JNI接口声明HelloJNI.h(javah命令)
  4. 使用C/C++编写JNI_Hello.c,实现HelloJNI.h中的接口方法
  5. 编译JNI_Hello.c为JNI_Hello.dll给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操作

参考

  1. 百度百科JNI
  2. JNI的使用:HelloWorld
  3. JNI 实战全面解析
  4. Eclipse集成JNI与AndroidNDK操作
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. linux下jni环境搭建 参考:http://blog.csdn.net/zhouyuanjing/article/details/7553706 2. 编写HelloJni工程,在主Activity(本例:HelloJni.java)里声明native函数: 如下: public native String stringFromJNI(); public native double add(double a, double b); public native double sub(double a, double b); public native double multi(double a, double b); public native double div(double a, double b); static { System.loadLibrary("hello-jni"); } 3. 在根目录下创建 jni 目录(mkdir jni). 4. 利用命令生成相应的头文件,在根目录下执行:javah -classpath bin/classes -d jni com.xxx.hello.HelloJni ————————————— ——————— ^ ^ 包名 类名 5. 编写相应的.c文件(hello-jni.c) #include<string.h> #include<jni.h> JNIEXPORT jstring JNICALL Java_com_xxx_hello_HelloJni_stringFromJNI(JNIEnv *env, jobject obj) { return(*env)->NewStringUTF(env, "Hello World from JNI !"); } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_add(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a + b; } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_sub(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a - b; } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_multi(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a * b; } JNIEXPORT jdouble JNICALL Java_com_xxx_hello_HelloJni_div(JNIEnv *env, jobject obj, jdouble a, jdouble b) { return a / b; } 6. jni目录下编写Android.mk文件 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY) 在根目录下运行:ndk-build xxx@xion-driver:~/android_env/eclipse/Workspace/HelloJni$ndk-build Install : libhello-jni.so => libs/armeabi/libhello-jni.so 可以看到已经正确的生成了libhello-jni.so共享库了。 7. Eclipse运行该工程即可。 ~~完~~

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KwCoding

谢了老板您讷~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值