idea算法java_在idea2018和vs2017平台下JNI编程调用C++算法(1)-环境搭建

本文详细介绍如何在Java 2018 IDEA和Visual Studio 2017环境下,通过JNI调用C++算法实现HelloWorld。简化步骤指导搭建过程,包括创建Java项目、生成头文件、C++代码编写与DLL生成,适合JNI初学者快速入门。
摘要由CSDN通过智能技术生成

在idea2018和vs2017平台下JNI编程调用C++算法(1)-环境搭建

JNI简介

JNI是Java Native Interface的简称,通过JNI,可以调用C++或C的程序(称为本地程序)。

应用场景

我认为应用场景可以用三个字概括“不得不”,即只有遇到必须跨语言的时候,才会选择JNI。从Java的场景出发,使用JNI意味着失去了跨平台的优势;从C++的角度想,可能需要将程序发布到安卓端等,而不得不采用JNI进行跨语言。

通过调研JNI,目前JNI的应用场景大部分是需要在安卓平台引入C/C++代码。也有人和我一样,正在开发的java系统需要调用一段C++的核心代码。于是,让我们愉快地入坑吧~

本文特色

本文主要讲解在idea2018和vs2017平台下搭建一套Java项目和C++解决方案,其中Java项目实现一个简单的HelloWorld功能,该功能正是通过JNI调用C++实现的。

作为一名JNI刚入坑小将,以及多年没写过(只在书本和考试中与其交手)C++的渣渣,写一个HelloWorld程序也是反复磨炼的过程。在反复磨炼过程中,我发现网上很多教程有些繁琐,需要将各种文件复制来粘贴去,稍有错误就要重新复制粘贴,实在让人恼火。所以本文介绍一种借助idea和vs平台尽量减少步骤的搭建方法。

环境介绍

操作系统:Win7专业版64bit

JDK:1.8

idea:2018

vs:2017

Tips:

windows系统注定了生成的动态链接库是dll文件

JDK10将javah工具取消,需要使用javac -h替代,这是与jdk8不同的地方

主要步骤

创建一个java项目,在其中编写一个带有native方法的类

利用idea生成.h头文件

在vs中创建一个动态链接库应用程序的解决方案

在解决方案中创建C++文件,实现头文件中的方法

生成动态链接库

回到idea,运行java项目,排错重复以上步骤直到运行成功

1.在idea创建java项目

首先本次项目主要想实现一个简单的HelloWorld,java程序声明sayHello函数,并将name当做参数传入。在C++中实现sayHello,将sayHello的文本传回给java程序。步骤如下

在idea创建java项目,在src目录下新建一个package,本文包为com.study,jni.demo.simple。

在包下创建一个类,用来编写native方法和main函数。

package com.study.jni.demo.simple;

import com.study.jni.demo.common.Constants;

public class SimpleHello {

public static native String sayHello(String name);

public static void main(String[] args) {

String name = "lucyChen";

String text = sayHello(name);

System.out.println("after native, java shows:" + text);

}

static {

// System.loadLibrary("JNICPPDEMO");

System.load(Constants.DLLPATH + "JNICPPDEMO.dll");

}

}

其中sayHello是一个静态方法,在前面标注为native代表了这是一个本地函数。

main函数中,调用sayHello函数。

下面的static代码块暂且不谈。

代码写好后,在生成头文件前,我们需要build一下项目,生成class文件,build后,可在左侧目录看到out/production目录下生成了对应class文件。

2.生成头文件

头文件可以使用命令行生成(见参考文献),或者熟悉格式后自己手写。但是正如前文的介绍,本文希望用一种简便的方式。所以我希望能够随便点一下就生成头文件(真的有点懒得)。于是,我找到了一种用idea工具生成头文件的方法,那就是External Tools。

External Tools其实就是将手动输入的命令存下来,本质也是运行javah,后面跟着配置参数,这些参数存在External Tools,避免每次手动输入。

添加External Tools.File->Settings->Tools->ExternalTools,点击添加

1e07b6ed0398e83801df7035550a38fc.png

编辑Tools

Name:Generate Header File

Program:$JDKPath$/bin/javah

Arguments:-jni -classpath $OutputPath$ -d ./jni $FileClass$

Working directory: $ProjectFileDir$

Name:External Tools的名称,喜欢什么起什么,只要自己明白

Program是javah工具所在地址,即jdk所在路径下的bin,该参数是指tool采用的运行工具是javah

Arguments设置的是javah的参数,具体可在命令行中查看javah的帮助,查看每个函数含义

9638f44ff72c87a693fc0f75ab36136c.png

Working directory:项目名称

生成头文件

保存工具后,右击需要生成头文件的类,即我们的SimpleHello,选择External Tool,点击我们刚刚创建的tool。

然后你就会发现我们的目录中多了一个jni文件夹,jni文件夹里面有一个名字长长的.h文件,成功!

0b6c4eadd904b36fa0a5cf8fb52be095.png

Tips:

该方法适用于jdk8,jdk10中取消了javah,适用javac -h。但是jdk10在使用External Tools时会报错。但是我的工作环境不可能用jdk10,所以我也没有钻进去研究了~

3.在vs中创建解决方案

长时间没接触过C++了,想当年(10年前)上学那会,我还只会用VC6.0刷刷题,而现在都要vs2017了,而我的C++知识早就忘得差不多了。虽然我作为一个小白,但是仍然阻挡不了我吐槽VS的中文翻译——解决方案,解决方,解决,解,角……emm,真变扭。废话不多说了,我们一起创建一个"解决方案"吧!

文件->新建->项目->Windows桌面->Windows桌面向导,输入名称。

479efaa819631b550763a2a542acdd13.png

选择应用程序类型,注意此处不要勾选预编译标头【参考】

800c8b2aff35bf85bd4706c51c5b69c9.png

设置项目包含目录

本来我是按照这篇文章复制jni.h等文件的,但是一直报错“找不到 源 文件 jni.h”。搞来搞去总是不成,后来才发现,我在vs2017直接复制,jni.h并没有到C++项目目录下,而是仍然在原来的目录里,这与java的ide很不同啊。虽然被这个问题搞到差点摔桌子,但我转念一想,在原来的目录下就还不错啊,省得我复制来复制去。于是刷刷刷设置了包含路径

点击项目,我的项目叫jniCppDemo,在菜单栏选择项目->属性->配置属性->VC++目录->包含目录

d927bde5c941b4a0aecf182107136c5d.png

设置包含路径

设置jni.h所在路径 C:\Program Files\Java\jdk1.8.0_181\include

设置jni_md.h所在路径 C:\Program Files\Java\jdk1.8.0_181\include\win32

设置刚刚生成头文件所在路径 D:\javaWorkspace\jniJavaDemo\jni

4.编写cpp文件

创建一个cpp文件,其中include jni.h,刚刚生成的头文件。如果上一步设置路径成功,这里不会报错。

在这个cpp,参考了这篇文章,实现sayHello,即获取参数name,并返回hello name给java程序。

#include "jni.h"

#include "stdio.h"

#include "string.h"

#include "com_study_jni_demo_simple_SimpleHello.h"

JNIEXPORT jstring JNICALL Java_com_study_jni_demo_simple_SimpleHello_sayHello(

JNIEnv *env, jclass cls, jstring j_str)

{

const char *c_str = NULL;

char buff[128] = { 0 };

jboolean isCopy;

c_str = env->GetStringUTFChars(j_str, &isCopy);

if (c_str == NULL)

{

printf("out of memory.\n");

return NULL;

}

printf("Java Str:%x %s %d %d\n", c_str, c_str, strlen(c_str), isCopy);

sprintf_s(buff, "hello %s", c_str);

env->ReleaseStringUTFChars(j_str, c_str);

return env->NewStringUTF(buff);

}

Tips

C++的调用方式和C的调用jni的方式不同,在jni.h中可以看出来,网上很多教程都是基于C的,我这里将其改成了C++的调用方式

5.生成dll文件

写好了cpp,让我们勇敢地生成dll文件吧。

参考文献里指出需要将解决方案平台改成64bit,那就改一下吧,毕竟我们需要运行在64位操作系统上。

eb6b6b1cb8862a7fb0c15ac5f8119d5e.png

然后右击项目生成/重新生成,就生成了dll文件。从控制台输出可看到dll的地址

dda28c9b2761f9c668a21d7e208bbe1f.png

6.运行java

生成dll文件后,让我们重新回到java项目,我们继续来讨论刚刚遗留的一段代码

static {

// System.loadLibrary("JNICPPDEMO");

System.load(Constants.DLLPATH + "JNICPPDEMO.dll");

}

含义很好理解,就是在java里面加载dll库。注释的方法是如果把dll库拷贝到java项目路径下,可以采用这种方式加载,不用写路径,不需要写后缀。

还有一种采用Systerm.load方式,这种需要指定库的位置并加上后缀。由于我在学习过程中,可能会遇到各种问题,来回修改和拷贝很麻烦,于是我采用了第二种方式,为了代码规范及好看,我新建了一个类存放dll的地址。

总结

至此,一个简单的HelloWorld的JNI项目搭建就打通了,本文采用idea2018和vs2017ide环境,实现了一种简便的搭建方法,这种方法可方便地应用在JNI学习过程中。

代码位置

后面会更新到github中,敬请期待

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值