使用JNA,让java调用原生代码
JNA定义:
JNA:java Native Access,是SUN公司开发的基于JNI的框架。JNI使得Java可以调用原生的c或者c++代码。
JNA与JNI(Java Native Interface)的差别:
性能:JNA在性能上不如JNI。由于JNA是在JNI的基础上封装了一层。
移植性:JNA的可移植性要好于JNI,由于开发人员不须要再编写作为代理的动态链接库。
使用:JNI使用native关键字,使用一个个java方法映射原生方法,利用System.loadLibrary;JNA使用一个java借口来代表动态链接库。使用Native.loadLibrary
JNA使用环境安装:
原生代码:使用C++或者C编写原生代码,或者使用已有的原生代码。在准备在java中使用的函数或者class前注明extern “C” __declspec(dllexport)。然后打包成动态链接库dll
Java代码:下载jna.jar,https://github.com/java-native-access/jna。然后把dll文件放在详细的project以下。
JNA使用:
1. 准备dll(这部分针对刚開始学习的人。可直接浏览第2部分)
我们从生成dll到利用JNA,使用Java调用dll一步一步解说。
首先生成dll。为了学习JNA。最好我们自己动手生成dll,我是使用Dev C++(http://sourceforge.net/projects/orwelldevcpp/) 这个工具来编写c++代码的。安装Dev C++之后,我们创建一个dllproject。
然后我们创建一个.h文件以及一个.cpp文件。我们须要在.h里面define:
#if BUILDING_DLL
#define DLLIMPORT extern "C" __declspec(dllexport)
#else
#define DLLIMPORT extern "C" __declspec(dllimport)
#endif
然后我们在.h定义两个Struct以及两个函数function:
struct UserStruct{
long id;
wchar_t* name;
int age;
};
DLLIMPORT
void sayUser(UserStruct* pUserStruct);
struct CompanyStruct{
long id;
wchar_t* name;
UserStruct* users[100];
int count;
};
DLLIMPORT
void sayCompany(CompanyStruct* pCompanyStruct);
这里须要注意,函数声明前须要加DLLIMPORT,这里DLLIMPORT等于extern “C” __declspec(dllexport),Struct前不须要做特殊的处理。
在.cpp文件里实现sayUser以及sayCompany两个函数:
void sayUser(UserStruct* pUserStruct)
{
std::wcout<<L"hello:"<<pUserStruct->name<<std::endl;
}
sayUser函数的功能是把UserStruct结构体中的的name打印出来
void sayCompany(CompanyStruct* pCompanyStruct)
{
std::wcout<<L"hello:"<<pCompanyStruct->name<<std::endl;
for(int i=0;i<pCompanyStruct->count;i++)
{
UserStruct* user=pCompanyStruct->users[i];
sayUser(user);
}
}
SayCompany函数的功能是把Company结构体中的name打印出来,同一时候把里面全部UserStruct成员的name打印出来。
然后我们在cpp文件里实现
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
return TRUE;
}
然后编译生成dll文件,由于我定义的project名字叫做JNATest,所以生成的dll文件叫做JNATest.dll。
2. Java使用JNA调用dll
我们须要创建一个interface,这里我们取名TestDll1,然后extends Library。我们须要把UserStruct和CompanyStruct两个结构体映射到java中,代码例如以下:
public class UserStruct extends Structure {
public static class ByReference extends UserStruct implements Structure.ByReference{};
public static class ByValue extends UserStruct implements Structure.ByValue{}
public NativeLong id;
public WString name;
public int age;
}
当中ByReference指的是指针,ByValue指的是值,然后以下三个字段分别相应.h文件里UserStruct中的三个字段,当中顺序一定不能错。由于作为内存传给c函数调用,读取时依照c中结构体的顺序来读,所以顺序一定不能错。
同理CompanyStruct在java中的映射例如以下:
public class CompanyStruct extends Structure{
public static class ByReference extends CompanyStruct implements Structure.ByReference{};
public static class ByValue extends CompanyStruct implements Structure.ByValue{};
public NativeLong id;
public WString name;
//须要使用toArray。由于java中的内存空间是不连续的。所以使用JNA提供的toArray方法生成连续的内存空间
public UserStruct.ByReference[] users=(UserStruct.ByReference[]) new UserStruct.ByReference().toArray(100);
public int count;
}
这里面有个须要特别注意的地方。否则会NULL错误。就是public UserStruct.ByReference[] users=(UserStruct.ByReference[]) new UserStruct.ByReference().toArray(100);这句话,假设改为public UserStruct.ByReference[] users=new UserStruct.ByReference[100],之后调用就会报错。原因是java的内存空间通常是不连续的,而我们须要连续的内存空间,这里须要使用JNA提供的toArray函数生成数组。
以下一段代码非常重要就是加载dll:
TestDll1 INSTANCE=(TestDll1) Native.loadLibrary("JNATest",TestDll1.class);
然后声明我们要在java中调用的原生函数:
public void sayUser(UserStruct userStruct);
public void sayCompany(CompanyStruct companyStruct);
然后我们创建一个Test.java,然后在main函数中測试能否调用原生函数。
首先測试sayUser:
UserStruct.ByReference userStruct=new UserStruct.ByReference();
userStruct.id=new NativeLong(100);
userStruct.age=30;
userStruct.name=new WString("SBY");
TestDll1.INSTANCE.sayUser(userStruct);
然后执行。会打印出hello:SBY
再測试sayCompany:
CompanyStruct.ByReference companyStruct=new CompanyStruct.ByReference();
companyStruct.id=new NativeLong(2);
companyStruct.name=new WString("hehe");
companyStruct.count=10;
UserStruct.ByReference pUserStruct=new UserStruct.ByReference();
pUserStruct.id=new NativeLong(90);
pUserStruct.age=99;
pUserStruct.name=new WString("sby");
//pUserStruct.write();
for(int i=0;i<companyStruct.count;i++){
companyStruct.users[i]=pUserStruct;
}
TestDll1.INSTANCE.sayCompany(companyStruct);
会输出一个hello:hehe和10个hello:sby
有些地方会说须要pUserStruct.write()这行代码,目的是把内存固定住,而不被GC释放掉,然而在我測试的时候没有加这一行也能准确执行。预计这个JNA提供的toArray函数有关。
以上就是我的JNA学习心得。之所以会在machine learning的博客中插入这样一篇,基本的目的是大多数的machine leanring的代码都是使用c或者c++编写。而一些场景会须要编写java程序。此时我们须要使用java来调用已经写好的c或者c++函数。
以上源码传送门:http://yun.baidu.com/share/link?
shareid=2278504517&uk=3977203577
使用JNA,让java调用原生代码的更多相关文章
- Android NDK开发篇(五):Java与原生代码通信(数据操作)
尽管说使用NDK能够提高Android程序的运行效率,可是调用起来还是略微有点麻烦.NDK能够直接使用Java的原生数据类型,而引用类型,由于Java的引用类型的实如今NDK被屏蔽了,所以在NDK使用 ...
- Android NDK开发篇(四):Java与原生代码通信(原生方法声明与定义与数据类型)
Java与原生代码通信涉及到原生方法声明与定义.数据类型.引用数据类型操作.NIO操作.訪问域.异常处理.原生线程 1.原生方法声明与定义 关于原生方法的声明与定义在上一篇已经讲一点了,这次具体分析一 ...
- Android NDK开发篇:Java与原生代码通信(原生方法声明与定义与数据类型)
Java与原生代码通信涉及到原生方法声明与定义.数据类型.引用数据类型操作.NIO操作.访问域.异常处理.原生线程 1.原生方法声明与定义 关于原生方法的声明与定义在上一篇已经讲一点了,这次详细分析一 ...
- windows和linux环境下java调用C++代码-JNI技术
最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结 ...
- 通过JNI实现java调用C代码和C代码调用java的代码
一.java调用C代码 1)java中需要声明调用的函数,也就是native方法,并通过System.LoadLibrary来调用dll或者so(C代码).实例代码如下: public class H ...
- Android NDK开发之C调用Java及原生代码断点调试(二)
上一篇中,我们主要学习了Java调用本地方法,并列举了两大特殊实例来例证我们的论据,还没学习的伙伴必须先去阅读下,本次的学习是直接在上一篇的基础上进行了.点击:Android NDK开发之从Java与 ...
- [JNA系列]Java调用Delphi编写的Dll之JNA使用
介绍 给大家介绍一个最新的访问本机代码的 Java 框架 —JNA . JNA(Java Native Access) 框架是一个开源的 Java 框架,是 SUN 公司主导开发的,建立在经典的 JN ...
- Android NDK开发篇(六):Java与原生代码通信(异常处理)
一.捕获异常 异常处理是Java中的功能.在Android中使用SDK进行开发的时候常常要用到.Android原生代码在运行过程中假设遇到错误,须要检測,并抛出异常给Java层.运行原生代码出现了问题 ...
- [JNA系列]Java调用Delphi编写的Dll之实例Delphi使用PWideChar
Delphi代码 unit UnitDll; interface uses StrUtils, SysUtils, Dialogs; function DoBusinessWide(pvData: P ...
随机推荐
- php 中引入邮箱服务 , 利用第三方的smtp邮件服务
项目中用短信通知有时间限制,对一些频率比较大的信息力不从心. 使用邮箱发送信息是个不错的选择\(^o^)/! 首先要注册一个邮箱,在邮箱设置里开通smtp功能. 简单介绍下smtp,大概就是第三方客户 ...
- oracle 表空间Tablespaces
1.表空间 一个数据库可以有多个表空间,一个表空间里可以有多个表.表空间就是存多个表的物理空间: 可以指定表空间的大小位置等. 创建表空间:create tablespace ts1 datafile ...
- MyBatis学习总结(4)——解决字段名与实体类属性名不相同的冲突
一.准备演示需要使用的表和数据 CREATE TABLE orders( order_id INT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(20), ...
- 百度语音识别服务 —— 语音识别 REST API 开发笔记
http://blog.csdn.net/lw_power/article/details/51771267
- JavaWeb初学者session的使用
使用request对象的getSession()获取session,如果session不存在则创建一个 HttpSession session = request.getSession();将数据存储 ...
- HDU 2421
由算术基本定理N=p1^e1*p2^e2....ps^es,可知一个素的因子个数为(e1+1)*(e2+1)*...*(es+1). 而N的一人因子必定也有n=p1^k1*p2^k2....*ps^k ...
- [TS] Class Properties Public, Private and Read Only Modifiers
In the constructor, we want to set the prop to readonly, you need to do like this: class Superhero { ...
- UI自动化
1.下载安装JDK,配置环境变量 2.下载eclips,并安装 3.下载jskuli截图工具,并安装 4.下载Jspec插件,将其放在eclipse路径下的\plugins文件夹中.(打开eclips ...
- Qt 3D教程(三)实现对模型材质參数的控制
Qt 3D教程(三)实现对模型材质參数的控制 蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/details/47131841.欢迎同行前来探讨. ...
- httpClient模拟登陆校内某系统
package com.huowolf; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpE ...