C++ 通过jni生成库供JAVA调用(下)–C++生成库并JAVA可以调用(windows)
项目上 JAVA通过C++库去调用硬件设备,需要用C++封装库,然后JAVA调用C++的库,这里描述JAVA调用C++库的过程。
这里实现C++生成库可让JAVA通过JNI去调用
编译环境:VS2015; eclipse/(使用命令行也操作可行,eclipse不熟悉,然后开始没有使用它)
语言: C++, JAVA
这个过程中遇到了一些坑,JAVA也是只会写个hello world ,然后在java调用库的时候会出现一些问题。
使用notepad++建立个.java文件,输出所需要实现的一些接口
使用文本来实现.java文件
在java文件里面声明在C++里面需要实现的接口或者已经存在的接口,数据类型需要适当的转换。
在D:\jni\java_jni\java_jni下建立个文件jniCppSDK.java
并输入一下内容
package java_jni;
public class jniCppSDK {
public native void sayHello();
public native int sum(int a, int b);
public native int max(int a, int b, int c);
static
{
System.loadLibrary("jniCppSDK");
}
public static void main(String[] args)
{
jniCppSDK test = new jniCppSDK();
test.sayHello();
System.out.println(test.sum(10, 21));
System.out.println(test.max(10, 12, 20));
System.out.println("hello JAVA");
}
}
或者使用eclipse来实现.java文件
该步骤和上个步骤的目的是一样的
- 打开eclipse – File – New – Java Project( 保存路径为
D:\jni\java_jni\java_jni_eclipse
,工程名称:java_jni_eclipse
) – Next – Finish- 在src处右键 New – Package ,Name 更改为
java_jni
- 在java_jni包处右键 New – Class , Class名字设置为
jniCppSDK
在jniCppSDK.java文件里面可以看到内容:
package java_jni;
public class jniCppSDK {
}
将之前代码添加到该Class里面
package java_jni;
public class jniCppSDK {
public native void sayHello();
public native int sum(int a, int b);
public native int max(int a, int b, int c);
static
{
System.loadLibrary("jniCppSDK");
}
public static void main(String[] args)
{
jniCppSDK test = new jniCppSDK();
test.sayHello();
System.out.println(test.sum(10, 21));
System.out.println(test.max(10, 12, 20));
System.out.println("hello JAVA");
}
}
利用javah 生成jni头文件
C++代码实现头文件这些接口,然后可以生成JAVA可以调用的库了
对使用notepad++之类的文本编辑器,进行操作
- 在jniCppSDK .java文件路径下,按住shift键+鼠标右键,点击在此处打开Powershell窗口,输出
javac jniCppSDK.java
,可以看到文件夹里面多出了jniCppSDK.class文件 - 由于.java文件使用
package java_jni;
声明,需要在java文件的父路径上进行操作,在shell里面输出cd ../
, 路径会回到D:\jni\java_jni
里面,然后输入javah java_jni.jniCppSDK
,来生成jni头文件,然后会在该路径下出现java_jni_jniCppSDK.h
文件
如果java文件里面没有package的声明的话,直接在java文件所在路径下javah java_jni.jniCppSDK
就可以了,因为java文件里面有package java_jni;
所以在生成头文件的时候需要在java文件的上层目录下进行操作
对使用eclipse的java文件操作
- 进入到eclipse工程里面,到
D:\jni\java_jni\java_jni_eclipse\src\java_jni
路径下,然后进入Powershell路径下’javac jniCppSDK.java’ - 然后
cd ../
,到上级目录下,运行javah java_jni.jniCppSDK
,然后该路径下会出现
java_jni_jniCppSDK.h
文件,
上面两种情况下生成 jni头文件,比较两种状况下得到的jni头文件,两者完全一样。
通过jni头文件和C++里面的程序进行对接
VS工程环境搭建
- 在
D:\jni\java_jni
里面,创建win32控制台的工程,工程名称为jniCppSDK,程序类型选择DLL,空项目。 - 将
java_jni_jniCppSDK.h
头文件添加到工程头文件里面,将testSDK.cpp
工程源文件(可以自己新建个源文件)
// testSDK.cpp : 定义 DLL 应用程序的导出函数。
//
#include <iostream>
#include "java_jni_jniCppSDK.h"
void helloSDK()
{
std::cout << "hello sdk" << std::endl;
}
int mySum(int a, int b)
{
return (a + b);
}
int myMax(int a, int b, int c)
{
int max = a;
if (max < b)
max = b;
if (max < c)
max = c;
return max;
}
此时编译的话,会出现无法打开 源 文件 “jni.h”的情况,需要将java的jni路径添加到附加包含目录配置属性 – C/C++ – 附加包含目录 添加
C:\Program Files\Java\jdk1.8.0_144\include\;C:\Program Files\Java\jdk1.8.0_144\include\win32
,注意:x86平台和x64平台的设置,可能是目录添加到x86里面,缺以x64平台运行的,所有还是会找不到
jni.h
文件,所以我两个平台都添加了附加包含目录。添加Source.def文件,输入以下内容,否则的话,链接不到方法。
LIBRARY "jniCppSDK"
EXPORTS
Java_java_1jni_jniCppSDK_sayHello @1
Java_java_1jni_jniCppSDK_sum @2
Java_java_1jni_jniCppSDK_max @3
编写代码
testSDK.cpp与生成的jni头文件接口对接,完成之后的代码:
// testSDK.cpp : 定义 DLL 应用程序的导出函数。
//
#include <iostream>
#include "java_jni_jniCppSDK.h"
void helloSDK()
{
std::cout << "hello sdk" << std::endl;
}
int mySum(int a, int b)
{
return (a + b);
}
int myMax(int a, int b, int c)
{
int max = a;
if (max < b)
max = b;
if (max < c)
max = c;
return max;
}
/*
* Class: java_jni_jniCppSDK
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_java_1jni_jniCppSDK_sayHello
(JNIEnv *, jobject)
{
helloSDK();
}
/*
* Class: java_jni_jniCppSDK
* Method: sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_java_1jni_jniCppSDK_sum
(JNIEnv * env , jobject obj, jint a, jint b)
{
return (jint)(mySum((int)a, (int)b));
}
/*
* Class: java_jni_jniCppSDK
* Method: max
* Signature: (III)I
*/
JNIEXPORT jint JNICALL Java_java_1jni_jniCppSDK_max
(JNIEnv * env, jobject obj, jint a, jint b, jint c)
{
return (jint)(myMax((int)a, (int)b, (int)c));
}
编译运行,生成dll文件。
将dll文件放到D:\jni\java_jni
路径下,命令行下运行java程序
D:\jni\java_jni> java java_jni.jniCppSDK
运行结果:
hello sdk
31
20
hello JAVA
将dll文件丢到eclipse工程路径下运行
运行结果:
hello sdk
31
20
hello JAVA
java调用C++库成功
附上测试源码: