JNI是什么
JNI,全称为Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互。即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。由于JNI是JVM规范的一部分,因此可以将我们写的JNI的程序在任何实现了JNI规范的Java虚拟机中运行。同时,这个特性使我们可以复用以前用C/C++写的大量代码JNI是一种在Java虚拟机机制下的执行代码的标准机制。代码被编写成汇编程序或者C/C++程序,并组装为动态库。也就允许非静态绑定用法。这提供了一个在Java平台上调用C/C++的一种途径。
JNI的应用场景
JNI的应用场景主要有:
- 需要提升效率时,C++的运行效率比java快,需要优化算法时可以考虑C++;
- 需要控制关键算法时,java源码容易被人破解,C++编译完了就不能反编译了;
- 需要控制授权时,可以考虑用C++编写授权部分代码。
如何在windows平台和Linux平台上进行JNI编程
在windows平台上进行JNI编程
首先确保在windows装有JDK(Java 语言的软件开发工具包)。本文的代码例子适配的windows JDK版本是jdk-8u181-windows-x64。本章节示范在windows平台上使用IntelliJ IDEA配合VisualStudio 2013进行JNI程序开发。
使用IntelliJ IDEA 2018新建一个Java工程,命名为WinJniDemo,如下图:
图1. 新建Java工程
图2.选择命令行程序模板
图3.填写工程名、路径以及包名
在包com.developerworks下新建Environment类和HelloJNI类。Environment类的作用在于统一加载Java程序所调用的C/C++编写的动态库,HelloJNI类是对应的C/C++动态库的Java接口类,代码如下:
//Environment.java
package com.developerworks;
public class Environment {
public static boolean initEnvironment() {
String OS = System.getProperty("os.name").toLowerCase();
if (OS.indexOf("windows") > -1) {
String strLibPath = "D:\\JavaCodeLib\\JNI_Learn\\hello\\OutDir\\Release_x64\\hello.dll";
System.load(strLibPath);
return true;
} else if (OS.indexOf("linux") > -1) {
String strLibPath = "/home/work/JavaCodeLib/JNI_Learn/hello/hello/hello.so";
System.load(strLibPath);
return true;
}
else if (OS.indexOf("linux") > -1) {
String strLibPath = "/home/work/JavaCodeLib/JNI_Learn/hello/hello/hello.so";
System.load(strLibPath);
return true;
}
else if (OS.indexOf("unix") > -1) {
String strLibPath = "/home/work/JavaCodeLib/JNI_Learn/hello/hello/hello.so";
System.load(strLibPath);
return true;
}
else if (OS.indexOf("solaris") > -1) {
String strLibPath = "/home/work/JavaCodeLib/JNI_Learn/hello/hello/hello.so";
System.load(strLibPath);
return true;
}
else if (OS.indexOf("mac") > -1) {
String strLibPath = "/Users/wang/javaPrj/hello.dylib";
System.load(strLibPath);
return true;
}
else
{
return false;
}
}
}
//HelloJNI.java
packagecom.developerworks;
public class HelloJNI {
public native void sayHello();
}
// 入口主函数调用代码
packagecom.developerworks;
public class Main {
public static void main(String[] args) {
// write your code here
Environment.initEnvironment();
// invoke the native method
newHelloJNI().sayHello();
}
}
在上面代码中函数System.load()是加载dll(windows)或so(Linux)库,只需名称即可,无需加入文件名后缀(.dll或.so)。native关键字将函数sayHello()声明为本地函数,由C/C++实现。具体的实现就在hello.dll(Windows平台)或hello.so(Linux平台)中。
接下来我们将根据HelloJNI类来生成C/C++程序所需要的头文件。JNI生成头文件是通过JDK中提供的javah工具来完成,javah工具在JAVA_HOME环境变量所指向的目录下的bin文件夹中。使用javah工具生成头文件的步骤如下:
一是打开windows的控制台程序,使用cd命令进入到WinJniDemo工程的src目录下:
二是执行javah命令生成头文件:javah -classpath . -jni -encoding UTF-8 com.developerworks.HelloJNI
命令成功执行后,在src文件夹下会有一个com_developerworks_HelloJNI.h。命令中-classpath .表示在当前目录下搜索类,-encoding UTF-8表示使用UTF-8作为生成的头文件的编码,com.developerworks.HelloJNI为指定的Java接口类。
//com_developerworks_HelloJNI.h代码
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_developerworks_HelloJNI */
#ifndef _Included_com_developerworks_HelloJNI
#define _Included_com_developerworks_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_developerworks_HelloJNI
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_developerworks_HelloJNI_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
从清单2可以看出C/C++动态库的接口头文件已经生成了。接下来我们使用vs2013创建一个Win32的动态库工程:
将com_developerworks_HelloJNI.h加到工程,在工程里添加一个com_developerworks_HelloJNI.cpp,目录结构如下图:
在工程的附加包含目录添加:KaTeX parse error: Undefined control sequence: \include at position 12: (JAVA_HOME)\̲i̲n̲c̲l̲u̲d̲e̲;(JAVA_HOME)\include\win32,如下图:
//com_developerworks_HelloJNI.cpp代码
#include "com_developerworks_HelloJNI.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_developerworks_HelloJNI_sayHello
(JNIEnv* env, jobject obj)
{
printf("Hello,JNI!\n");
}
编译工程生成dll文件。在IntelliJ IDEA 2018编译运行Java工程WinJniDemo,得到下面的运行效果:
在Linux平台上进行JNI编程
首先确保在Linux装有gcc和JDK(Java 语言的软件开发工具包)。本文的代码例子适配的Linux JDK版本是jdk-8u144-linux-x64。先用gcc编译C/C++程序生成so库,执行下面的编译脚本:
gcc com_developerworks_HelloJNI.cpp -std=c++11 -fPIC -shared -I/usr/local/java/jdk1.8.0_144/include -I/usr/local/java/jdk1.8.0_144/include/linux -lm -o ./hello.so
然后使用Eclipse编译运行之前建好的Java工程,运行结果如下:
后续支持,请添加VX: explorer101