一、新建Java工程,在Java类中声明一个native的方法

新建Java项目

在新建的项目中创建packet(包),并且在包下创建一个Class(类)。

接下来,在该类中添加如下代码:

1
2
3
4
5
6
7
8
9
public class JavaInvodeCPlus {
 
//声明为native,表明是有外部来实现的
 
public native String returnHelloWorldToUpcase(String string);
 
public native void sayHelloWolrd();
 
}

二、使用Javah命令生成native方法的声明的C/C++头文件

进入该项目所在的位置,博主这里的位置是D:\00Coding\my-space\JavaInvokeCPlus

接着进入bin目录下,找到该packet下存在一个.class文件

我们需要用javah命令来生成头文件。回到bin目录下,因为这里涉及到包名,所以必须在包目录下来。按住shift键,同时在文件夹内空白处右击,可以进入命令行。当然,你也可以一步步进入到该路径下。

这里需要注意的是,文件的末尾不加上.class后缀。然后我们可以看到在bin目录下多了一个.h头文件。

打开我们可以看到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_cjzheng_service_JavaInvodeCPlus */
  
#ifndef _Included_com_cjzheng_service_JavaInvodeCPlus
#define _Included_com_cjzheng_service_JavaInvodeCPlus
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_cjzheng_service_JavaInvodeCPlus
 * Method:    returnHelloWorldToUpcase
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_cjzheng_service_JavaInvodeCPlus_returnHelloWorldToUpcase
  (JNIEnv *, jobject, jstring);
  
/*
 * Class:     com_cjzheng_service_JavaInvodeCPlus
 * Method:    sayHelloWolrd
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_cjzheng_service_JavaInvodeCPlus_sayHelloWolrd
  (JNIEnv *, jobject);
  
#ifdef __cplusplus
}
#endif
#endif

这就是头文件的内容,现在我们来分析一下这个头文件的结果。有图有真相:

三、引入生成的C++头文件来编写C++源文件

博主这里使用的VS2015,就是喜欢用新的软件。任性也是一种罪过…

新建项目

点击确定后,点击下一步,进入如下界面

点击完成,进入。

接着我们需要引入的头文件有三个,一个是刚刚使用javah生成的头文件,剩下两个需要在JDK中拷贝,博主这里使用的是JDK7的,现在将这三个头文件拷贝到C++工程的目录下。jdk的头文件在jdk的安装目录下,这两个文件的目录如下:

得到C++项目的文件如下:

然后将这三个头文件导入vs2015中

此时我们看到,貌似报错了呀!别着急,想必学过C++的人都知道这是系统库和自定义库的区别。这里将<>改成“”就可以啦!

接着我们需要做的就是实现这两个需要实现的方法,新建一个cpp文件

引入我们生成的.h文件,然后实现它。

附上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<iostream>
#include"com_cjzheng_service_JavaInvodeCPlus.h"
#include <string>
#include <cctype>
#include <algorithm>
using namespace std;
  
/*
* Class:     com_cjzheng_service_JavaInvodeCPlus
* Method:    returnHelloWorldToUpcase
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_cjzheng_service_JavaInvodeCPlus_returnHelloWorldToUpcase
(JNIEnv *, jobject, jstring str) {
    return str;
}
  
/*
* Class:     com_cjzheng_service_JavaInvodeCPlus
* Method:    sayHelloWolrd
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_cjzheng_service_JavaInvodeCPlus_sayHelloWolrd
(JNIEnv *, jobject) {
    cout << "Hello World" << endl;
}

报这个提示,不要惊慌,关闭就行。只要底下编译成功就可以了。

到该项目的路径下,我们可以找到生成了一个dll文件

四、将DLL文件加入到PATH环境变量下

这里有两种方法,一种是在环境变量中path里追加上这个dll所在的路径;一种是将这个dll文件拷贝到已经存在于path中的路径下。博主这里采用后者,因为博主的jdk配置了环境变量。所以直接将该dll拷贝到jdk的bin目录下。

所以我这里就将这个dll拷贝到jdk8的路径下,读者不要混淆,虽然博主这里采用jdk7,但是那是eclipse指定的项目jdk环境,是可以指定的,不要和环境变量这个混淆。

好了,离成功不远了!但是越是到快成功的时候,越要耐住性子。

五、Java类中加载DLL,然后调用声明方法

回到Java项目中,写一个测试类,调用该dll,执行相应方法,就可以啦!

附上代码:

public class TestMain {

/**

* @Title: TestMain

* @Description: TODO

* @param args

* void

* @Date: 2016年6月18日

* @author:zhengchaojie

*/

public static void main(String[] args) {

System.loadLibrary("CplusImplement");// 不需要加入.dll后缀

JavaInvodeCPlus javaInvodeCPlus = new JavaInvodeCPlus();

System.out.println(javaInvodeCPlus.returnHelloWorldToUpcase("QQQQQQQ"));

}

}

很幸运,成功了,而且不带有任何麻烦。bingo!!!

六、常见失败

1、找不到指定的dll文件:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no CplusImplement in java.library.path

at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1886)

at java.lang.Runtime.loadLibrary0(Runtime.java:849)

at java.lang.System.loadLibrary(System.java:1088)

at com.cjzheng.service.TestMain.main(TestMain.java:20)

解决方案:确认该dll文件名是否正确,是否在环境变量中添加了可以找到该dll的变量。

2、方法名不对,或者参数个数不对,或者参数形式不对(这里是博主另外一个项目的错误)

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.cjzheng.util.CPlusMethod.SAASChooseAntenna(DDDDDDDDDD)I

3、由于A机子上不同C++编译器生成的dll,在B机器上缺少相应的dll文件导致错误;

Exception in thread "main" java.lang.UnsatisfiedLinkError: D:\Program Files\Java\jdk1.8.0_60\bin\CPlusMethod.dll: Can't find dependent libraries

at java.lang.ClassLoader$NativeLibrary.load(Native Method)

at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1965)

at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1890)

at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1880)

at java.lang.Runtime.loadLibrary0(Runtime.java:849)

at java.lang.System.loadLibrary(System.java:1088)

at com.cjzheng.util.CPlusMethod.(CPlusMethod.java:12)

at com.cjzheng.service.impl.TestMain.main(TestMain.java:21)

这里介绍一种比较简便的方法来解决这个问题。

例如如果A机器是VS2010,该DLL是使用VS2010编译,在本机上测试通过,但换了一个机子,就报上面的错误。如果报这个错误,首先可以肯定的是,库得路径都是对的。这时候,如果你去安装VS2010,问题肯定就解决了,但是VS2012装起来太麻烦了。所以这里的解决方法是在A机器上使用VS2010编译C++的DLL时,去掉/MD选项。具体步骤:

JAVA java调用C++动态链接库dll,有详细过程。VS2015+Eclipse以及失败解决方案的更多相关文章

  1. Atitit.java jna  调用c  c++ dll的原理与实践  总结  v2  q27

    Atitit.java jna  调用c  c++ dll的原理与实践  总结  v2  q27 1. Jna简单介绍1 2. Jna范例halo owrld1 3. Jna概念2 3.1. (1)需 ...

  2. java中调用本地动态链接库(*.DLL)的两种方式详解和not found library、打包成jar,war包dll无法加载等等问题解决办法

    我们经常会遇到需要java调用c++的案例,这里就java调用DLL本地动态链接库两种方式,和加载过程中遇到的问题进行详细介绍 1.通过System.loadLibrary("dll名称,不 ...

  3. (转)java程序调用内存变化过程分析(详细)

    原博地址: https://blog.csdn.net/Myuhua/article/details/81385609 (一)不含静态变量的java程序运行时内存变化过程分析 代码: package ...

  4. java jna 调用windows动态链接库

    import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; import com.sun.j ...

  5. wincc C脚本如何调用第三方动态链接库dll

    就Wincc本身脚本功能而言并不强大,但是wincc 脚本提供了第三方接口,如通用的Kernel32.dll,User32.dll,Gdi32.dll,大家如果对这些API接口感兴趣,可网上查找关于w ...

  6. OpenKM6.2.5的安装和配置详细过程(附启动失败原因)

    继上文“解决OpenKM启动失败的详细历程”过后,这几天一直在使用OpenKM,OpenKM使用起来很简单,但是一些相关配置什么的中文资料较少,且有的资料欠缺正确性,存在误导性,下面就简单将配置过程和 ...

  7. java中调用dll文件的两种方法

    一中是用JNA方法,另外是用JNative方法,两种都是转载来的, JNA地址:http://blog.csdn.net/shendl/article/details/3589676   JNativ ...

  8. JNI编程(二) —— 让C++和Java相互调用(1)

    自己在外面偷偷的算了下,又有将近两个月没更新过blog了.趁着今天有兴致,来更新JNI编程的第二篇文章.在第一篇里,大概介绍了JNI的特点.用途和优劣.并且做一个最简单的JNI的例子,不过说实话那个例 ...

  9. R语言- 实验报告 - 利用R语言脚本与Java相互调用

    一. 实训内容 利用R语言对Java项目程序进行调用,本实验包括利用R语言对java的.java文件进行编译和执行输出. 在Java中调用R语言程序.本实验通过eclipse编写Java程序的方式,调 ...

随机推荐

  1. mysql几个常见错误记录

    select时找不到表:大小写问题 show variables like '%lower_case_table_names%'; MySQL表名大小写敏感导致的问题 使用help_topic时的se ...

  2. celery中配置redis密码时的ValueError: invalid literal for int() with base 10: 'xxxx'

    原配置: celery_broker = 'redis://:xxxx#xxxx@172.17.0.1:6379/0' # docker0 错误原因: 密码中不能有 # ? 等特殊字符 (无语O__O ...

  3. [网络流24题] 洛谷P2761 软件补丁问题

    题意:某公司发现其研制的一个软件中有 n个错误,随即为该软件发放了一批共 m 个补丁程序.对于每一个补丁 i ,都有 2 个与之相应的错误集合 B1(i)和 B2(i),使得仅当软件包含 B1(i)中 ...

  4. Django 自定义扩展命令

    import datetime import logger from django.conf import settings from django.db.models import Q from d ...

  5. web框架express学习一

    服务端 node app.jsapp.jslet express = require("express"); let http = require("http" ...

  6. Dart编程实例 - 相等和关系操作符

    Dart编程实例 - 相等和关系操作符 void main() { var num1 = 5; var num2 = 9; var res = num1>num2; print('num1 gr ...

  7. PHP反序列化漏洞研究

    序列化 序列化说通俗点就是把一个对象变成可以传输的字符串 php serialize()函数 用于序列化对象或数组,并返回一个字符串.序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结 ...

  8. This inspection warns about local variables referenced before assignment.

    关于 local variable 'has' referenced before assignment 问题 今天在django开发时,访问页面总是出现错误提示“local variable 'ha ...

  9. Dubbo入门到精通学习笔记(二):Dubbo管理控制台、使用Maven构建Dubbo的jar包、在Linux上部署Dubbo privider服务(shell脚本)、部署consumer服务

    文章目录 Dubbo管理控制台 1.Dubbo管理控制台的主要作用: 2.管理控制台主要包含: 3.管理控制台版本: 安装 Dubbo 管理控制台 使用Maven构建Dubbo服务的可执行jar包 D ...

  10. git分布式版本控制系统权威指南学习笔记(六):git reset、get stash、git checkout总结

    文章目录 1. 概述 2. 如何把修改暂存起来,留着以后使用? 2.1 使用场景 2.2 git stash 暂存进度 2.3 查看进度 2.4 恢复进度 3. 如何撤销工作区的修改? 4. 如何把暂 ...