Java程序通过JNI调用C++程序的方法

本文介绍了Java Native Interface (JNI) 的概念,以及如何在Windows和Linux平台上进行JNI编程。在Windows上,使用IntelliJ IDEA和Visual Studio 2013创建Java和C++项目,通过javah生成头文件并编译DLL。在Linux上,使用gcc编译C++代码生成SO库,然后在Eclipse中运行Java工程验证调用。
摘要由CSDN通过智能技术生成

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的应用场景主要有:

  1. 需要提升效率时,C++的运行效率比java快,需要优化算法时可以考虑C++;
  2. 需要控制关键算法时,java源码容易被人破解,C++编译完了就不能反编译了;
  3. 需要控制授权时,可以考虑用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工程
新建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目录下:
切换到src目录下
  二是执行javah命令生成头文件:javah -classpath . -jni -encoding UTF-8 com.developerworks.HelloJNI
执行javah命令生成头文件
  命令成功执行后,在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的动态库工程:
Win32动态库工程
  将com_developerworks_HelloJNI.h加到工程,在工程里添加一个com_developerworks_HelloJNI.cpp,目录结构如下图:
Win32动态库工程目录
  在工程的附加包含目录添加:KaTeX parse error: Undefined control sequence: \include at position 12: (JAVA_HOME)\̲i̲n̲c̲l̲u̲d̲e̲;(JAVA_HOME)\include\win32,如下图:
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,得到下面的运行效果:
IntelliJ IDEA上的运行效果

在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工程,运行结果如下:
Eclipse上的运行效果
  后续支持,请添加VX: explorer101

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

clever101

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值