JNI HelloWorld的例子

1.编写JAVA代码

新建Project 编写Hello.java类

这里写图片描述

Hello.java

package com.hqq;

/**
 * Hello
 * Created by heqianqian on 2017/4/15.
 */
public class Hello {

    //定义本地方法
    private native void sayHello();

    public static void main(String[] args) {
        //调用动态链接库
        System.loadLibrary("Hello");
        Hello hello = new Hello();
        hello.sayHello();
    }
}

函数System.loadLibrary()是加载dll(windows)或so(Linux)库,只需名称即可,无需加入文件名后缀(.dll或.so)。

native关键字将函数sayHello()声明为本地函数,由C/C++实现。具体的实现就在hello.dll(Windows平台)或hello.so(Linux平台)中

2.生成JNI头文件

1 ) 手动输入javah指令

JNI生成头文件是通过JDK中提供的javah来完成,javah在 {JDKHome}/bin目录中。用法如下:

javah -jni -classpath (搜寻类目录) -d (输出目录) (类名)

需要注意的是,使用javah来生成头文件(.h)时,-classpath指定的是编译后的java文件(.class)的目录,而不是源文件(.java)的目录,因此在使用javah指令之前,先build一下项目(或直接运行一下)。此时会生称out目录,所有编译后的文件都会存放在这个目录中。

这里写图片描述

在IDEA的控制台下输入指令

这里写图片描述

javah -classpath F:\Workspaces\JavaWorkspace\JNIDemo1\out\production\JNIDemo1 -d F:\Workspaces\JavaWorkspace\JNIDemo1\lib com.hqq.Hello

可以看到在lib文件夹下生成了com_hqq_Hello.h文件

这里写图片描述

这里注意两点

javah -jni -classpath (搜寻类目录) -d (输出目录) (类名)
  1. 搜索类目录不要进入包目录 否则会提示找不到类
  2. 类名要写全且不用加.java后缀

生成的头文件内容如下

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

#ifndef _Included_com_hqq_Hello
#define _Included_com_hqq_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_hqq_Hello
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_hqq_Hello_sayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

接下来我们只需实现Java_com_huachao_java_HelloJNI_sayHello(JNIEnv *, jobject)即可。

仔细观察就会发现这个函数名称是有规律的,即

    Java_<包>_<类名>_<函数名>

JNIEXPORT和JNICALL这两个宏定义暂时不用管。JNIEnv 和jobject后面系列文章会详细介绍,这里暂时不理会。

2 ) 一键生成头文件

点击File>Settings>Tools>External Tools:

这里写图片描述

添加一个新的External Tools:

这里写图片描述

在HelloJNI.java文件中点击右键>External Tools>Generate Header File

这里写图片描述

这里写图片描述

点击生成,可以看到Terminal窗口会自动运行指令

3. 编写C文件并编译成dll(或so)文件

命令行生成dll

在jni目录下新建Hello.c文件 实现Java_com_huachao_java_HelloJNI_sayHello(JNIEnv *, jobject)函数

##include<jni.h>
#include<stdio.h>
#include"com_hqq_Hello.h"

/*
 * Class:     com_hqq_Hello
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_hqq_Hello_sayHello(JNIEnv *env, jobject obj){
    printf("hello,jni!");
    printf("hello,world!");
    return ;
}

接下来就是使用GCC对HelloJNI.c编译,在Terminal窗口输入如下:

    gcc -c jni/Hello.c

提示找不到 jni.h

F:\Workspaces\JavaWorkspace\JNIDemo1>gcc -c jni/Hello.c
jni/Hello.c:1:16: fatal error: jni.h: No such file or directory
 #include<jni.h>
                ^
compilation terminated.

将JDK目录中的include目录加入

gcc -c -I"E:\Program Files\Java\jdk1.8\include" jni/Hello.c

又提示找不到 jni_md.h

F:\Workspaces\JavaWorkspace\JNIDemo1>gcc -c -I"E:\Program Files\Java\jdk1.8\include" jni/Hello.c
In file included from jni/Hello.c:1:0:
E:\Program Files\Java\jdk1.8\include/jni.h:45:20: fatal error: jni_md.h: No such file or directory
 #include "jni_md.h"

继续将JDK目录中的include/win32加入

gcc -c -I"E:\Program Files\Java\jdk1.8\include" -I"E:\Program Files\Java\jdk1.8\include\win32" jni/Hello.c

这次运行成功 在项目根目录下生成了Hello.o

接下来是将HelloJNI.o转为HelloJNI.dll,即转为windows平台下的动态链接库

输入

gcc -Wl,--add-stdcall-alias -shared -o hello.dll Hello.o

结果项目目录中生成了hello.dll文件:

这里写图片描述

一键生成dll

File>Settings>Tools>External Tools>+

输入内容

name:Generate DLL
Program:<GCC路径>
Parameters:-Wl,--add-stdcall-alias -I"$JDKPath$\include" -I"$JDKPath$\include\win32" -shared -o ./lib/$FileNameWithoutExtension$.dll ./jni/$FileNameWithoutExtension$.c
Working Directory:$ProjectFileDir$

这里配置将jni下.c文件生成.dll文件放在lib目录下

首先看生成dll文件前项目目录

这里写图片描述

生成之后

这里写图片描述

4. 运行

这里写图片描述

5.可能出现的错误

java.library.path找不到dll的错误

Exception in thread "main" java.lang.UnsatisfiedLinkError: no Hello in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
    at java.lang.System.loadLibrary(System.java:1122)
    at com.hqq.Hello.main(Hello.java:14)

即找不到我们生成的dll文件。因为在Windows中JVM的java.library.path属性即为环境变量Path指定的目录,而我们生成的dll并未放入到Path指定的任何一个目录中,因此我们需要告诉JVM,dll文件在哪个目录中

点击Run > Edit Configurations…,如下:

在VM options中加入java.library.path,指定dll(或so)文件所在的目录,比如本文中dll放在项目目录中的lib中,如下:

-Djava.library.path=F:\Workspaces\JavaWorkspace\JNIDemo1\lib

无法识别__int64类型错误

 error: unknown type name '__int64'
 typedef __int64 jlong;

出现这个错误的人一般是使用Cygwin GCC的人,这是因为Cygwin GCC不认识__int64类型,找到/include/win32/jni_md.h,找到typedef __int64 jlong;并修改为:

#ifdef __GNUC__
typedef long long jlong;
#else
typedef __int64 jlong;
#endif

或者是编译时将__int64加入,如下:

> gcc-3 -D __int64="long long" -mno-cygwin -Wl,--add-stdcall-alias 
  -I"<JAVA_HOME>\include" -I"<JAVA_HOME>\include\win32" -shared -o hello.dll HelloJNI.c

64-bit mode not compiled

HelloJNI.c:1:0: sorry, unimplemented: 64-bit mode not compiled in
 #include <jni.h>

出现这个错误是因为,JDK版本是64位,而GCC编译器编译出的dll(或so)是32位,只需换个64位版本的GCC即可


参考文章:

http://www.jianshu.com/p/44cbe11e5d35

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值