`
daigong
  • 浏览: 114072 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论
阅读更多
http://hi.baidu.com/dflgq/blog/item/b199cc5246f680561138c263.html


介绍
给大家介绍一个最新的访问本机代码的Java框架—JNA。

JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。

JNA项目地址:https://jna.dev.java.net/


非常强大、易用,功能上类似与.NET的P/Invoke。




不堪回首的JNI
我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的。

如果有一个现有的.dll/.so文件,如果使用JNI技术调用,我们首先需要另外使用C语言写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 dll/so中公布的函数。

然后再在Java中载入这个适配器dll/so,再编写Java   native函数作为dll中函数的代理。

经过2个繁琐的步骤才能在Java中调用本地代码。

因此,很少有Java程序员愿意编写调用dll/.so库中的原生函数的java程序。这也使Java语言在客户端上乏善可陈。可以说JNI是Java的一大弱点!


.NET平台上强大的P/Invoke
而在.NET平台上,强大的P/Invoke技术使我们Java程序员非常羡慕。使用P/Invoke技术,只需要使用编写一个.NET函数,再加上一个声明的标注,就可以直接调用dll中的函数。

不需要你再使用C语言编写dll来适配。



不逊于P/Invoke的JNA
现在,不需要再羡慕.NET的P/Invoke机制了。JNA把对dll/.so共享库的调用减少到了和P/Invoke相同的程度。


使用JNA,不需要再编写适配用的.dll/.so,只需要在Java中编写一个接口和一些代码,作为.dll/.so的代理,就可以在Java程序中调用dll/so。



JNA快速启动


     现在让我们直接进入JNA的世界。


你只需要下载一个jar包,就可以使用JNA的强大功能方便地调用动态链接库中的C函数。

1,下载jna.jar。

在这里https://jna.dev.java.net/servlets/ProjectDocumentList?folderID=7408&expandFolder=7408&folderID=0



2,现在你已经可以使用JNA了。

为了方便你参考JNA的java类库,我制作了《JNA3.09API参考手册》,是CHM格式的。你可以到这里下载 http://download.csdn.net/source/900438





JNA例子


例子1   
现在让我们运行一个JNA程序,感受它的强大威力。

1,在Java项目中引入jna.jar包。

2,创建一个类:


import com.sun.jna.Library;

import com.sun.jna.Native;

import com.sun.jna.Platform;


/** Simple example of native library declaration and usage. */

public class HelloWorld {


    public interface CLibrary extends Library {

        CLibrary INSTANCE = (CLibrary)

            Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),

                               CLibrary.class);

  

        void printf(String format, Object... args);

    }


    public static void main(String[] args) {

        CLibrary.INSTANCE.printf("Hello, World\n");

        for (int i=0;i < args.length;i++) {

            CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);

        }

    }

}





3,执行,可以看到控制台中打印出了

Hello, World


    但是,请注意,这个程序实际上是使用msvcrt.dll这个C运行时库中的printf函数打印出上面这些字符的。


    看,多简单,不需要写一行C代码,就可以直接在Java中调用外部动态链接库中的函数!


例子2   


    上面那个例子使用了操作系统自带的动态链接库,现在我们再自己写一个动态链接库试试。



1,在VS中选择C++语言,然后选择创建一个Win32程序。 选择dll类型。


2,发布的C函数是:


#define MYLIBAPI extern   "C"     __declspec( dllexport )


MYLIBAPI void say(wchar_t* pValue);



这个函数的实现是:


void say(wchar_t* pValue){

     std::wcout.imbue(std::locale("chs"));


     std::wcout<<L"上帝说:"<<pValue<<std::endl;

}


它需要传入一个Unicode编码的字符数组。然后在控制台上打印出一段中文字符。


3,生成dll。然后把生成的dll文件复制到Eclipse项目中,放在项目下面。

4,在Eclipse中编写以下代码:


import com.sun.jna.Library;

import com.sun.jna.Native;

import com.sun.jna.WString;


/**

* @author 沈东良 Edward Shen shendl_s@hotmail.com

* 2008-11-23 下午05:07:14

*TestDll1.dll

*/

public class TestDll1Service {


         public interface TestDll1 extends Library {

                   /**

                    * 当前路径是在项目下,而不是bin输出目录下。

                    */

                   TestDll1 INSTANCE = (TestDll1)Native.loadLibrary("TestDll1", TestDll1.class);

                   public void say(WString value);

                 

         }

         /**

          *

          */

         public TestDll1Service() {

                   // TODO Auto-generated constructor stub

         }


         /**

          * @param args

          */

         public static void main(String[] args) {

                   // TODO Auto-generated method stub

                 

                   TestDll1.INSTANCE.say(new WString("Hello World!"));

                   System.out.println("HHEEH我我们无法万恶");

         }


}


5,执行这个Java类。可以看到控制台下如下输出:

上帝说:Hello World!

HHEEH我我们无法万恶


6,上面一行是C语言使用C++的std::wcout输出的。

下面一行是Java语言输出的。




JNA技术解密
JNA工作原理
JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。

原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。

JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射。你不再需要编写C动态链接库。

当然,这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。可能速度会降低几倍。但影响不大。


JNA技术难点



1,当前路径是在项目下,而不是bin输出目录下。

2,数据结构的对应关系:

Java—C和操作系统数据类型的对应表
Java Type
C Type
Native Representation

boolean
int
32-bit integer (customizable)

byte
char
8-bit integer

char
wchar_t
platform-dependent

short
short
16-bit integer

int
int
32-bit integer

long
long long, __int64
64-bit integer

float
float
32-bit floating point

double
double
64-bit floating point

Buffer
Pointer
pointer
platform-dependent (32- or 64-bit pointer to memory)

<T>[] (array of primitive type)
pointer
array
32- or 64-bit pointer to memory (argument/return)
contiguous memory (struct member)

除了上面的类型,JNA还支持常见的数据类型的映射。

String
char*
NUL-terminated array (native encoding or jna.encoding)

WString
wchar_t*
NUL-terminated array (unicode)

String[]
char**
NULL-terminated array of C strings

WString[]
wchar_t**
NULL-terminated array of wide C strings

Structure
struct*
struct
pointer to struct (argument or return) (or explicitly)
struct by value (member of struct) (or explicitly)

Union
union
same as Structure

Structure[]
struct[]
array of structs, contiguous in memory

Callback
<T> (*fp)()
function pointer (Java or native)

NativeMapped
varies
depends on definition

NativeLong
long
platform-dependent (32- or 64-bit integer)

PointerType
pointer
same as Pointer




JNA编程过程


JNA把一个dll/.so文件看做是一个Java接口。

Dll是C函数的集合、容器,这正和接口的概念吻合。


    我们定义这样一个接口,

public interface TestDll1 extends Library {

                   /**

                    * 当前路径是在项目下,而不是bin输出目录下。

                    */

                   TestDll1 INSTANCE = (TestDll1)Native.loadLibrary("TestDll1", TestDll1.class);

                   public void say(WString value);

                 

         }



如果dll是以stdcall方式输出函数,那么就继承StdCallLibrary。否则就继承默认的Library接口。


接口内部需要一个公共静态常量:instance。


TestDll1 INSTANCE = (TestDll1)Native.loadLibrary("TestDll1", TestDll1.class);


通过这个常量,就可以获得这个接口的实例,从而使用接口的方法。也就是调用外部dll的函数!


注意:

1,Native.loadLibrary()函数有2个参数:

    1,dll或者.so文件的名字,但不带后缀名。这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。

搜索dll的路径是:

1)项目的根路径

2)操作系统的全局路径、

3)path指定的路径。


2,第二个参数是本接口的Class类型。


JNA通过这个Class类型,根据指定的dll/.so文件,动态创建接口的实例。


2,接口中你只需要定义你需要的函数或者公共变量,不需要的可以不定义。

public void say(WString value);


参数和返回值的类型,应该和dll中的C函数的类型一致。

这是JNA,甚至所有跨平台调用的难点。


这里,C语言的函数参数是:wchar_t*。

JNA中对应的Java类型是WStirng。



所有跨平台、跨语言调用的难点
有过跨语言、跨平台开发的程序员都知道,跨平台、语言调用的难点,就是不同语言之间数据类型不一致造成的问题。绝大部分跨平台调用的失败,都是这个问题造成的。

关于这一点,不论何种语言,何种技术方案,都无法解决这个问题。

这需要程序员的仔细开发和设计。这是程序员的责任。


常见的跨平台调用有:
1,Java调用C语言编写的dll、.so动态链接库中的函数。

2,.NET通过P/Invoke调用C语言编写的dll、.so动态链接库中的函数。

3,通过WEBService,在C,C++,Java,.NET等种种语言间调用。

    WebService传递的是xml格式的数据。


即使是强大的P/Invoke或者WebService,在遇到复杂的数据类型和大数据量的传递时,还是会碰到很大的困难。


因为,一种语言的复杂的数据类型,很难用另一种语言来表示。这就是跨平台调用问题的本质。
如,WEBService调用中,很多语言,如Java,.NET都有自动实现的Java/.NET类型和XML类型之间的映射的类库或者工具。

但是,在现实的编程环境中,如果类型非常复杂,那么这些自动转换工具常常力不从心。

要么Object-XML映射错误。

要么映射掉大量的内存。


因此,我个人对这些Object-XML映射框架相当不感冒。

我现在使用WEBService,都是直接手工使用xml处理工具提取xml中的数据构建对象。或者反过来,手工根据Object中的属性值构建xml数据。



Java和C语言之间的调用问题,也是如此。

Java要调用C语言的函数,那么就必须严格按照C语言要求的内存数量提供Java格式的数据。要用Java的数据类型完美模拟C语言的数据类型。

JNA已经提供了大量的类型匹配C语言的数据类型。




跨平台、跨语言调用的第一原则:就是尽量使用基本、简单的数据类型,尽量少跨语言、平台传递数据!
只有你才能拯救你自己。

如果在你的程序中,有复杂的数据类型和庞大的跨平台数据传递。那么你必须另外写一些Façade接口,把需要传递的数据类型简化,把需要传递的数据量简化。

否则,不论是实现的难度还是程序的性能都很难提高。





JNI还是不能废
我们已经见识了JNA的强大。JNI和它相比是多么的简陋啊!

但是,有些需求还是必须求助于JNI。

JNA是建立在JNI技术基础之上的一个框架。

使用JNI技术,不仅可以实现Java访问C函数,也可以实现C语言调用Java代码。

而JNA只能实现Java访问C函数,作为一个Java框架,自然不能实现C语言调用Java代码。此时,你还是需要使用JNI技术。

JNI是JNA的基础。是Java和C互操作的技术基础。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shendl/archive/2008/12/23/3589676.aspx
分享到:
评论

相关推荐

    jna-4.5.1 , jna-4.5.1-sources , jna-platform-4.5.1 jar包

    jna-4.5.1 , jna-4.5.1-sources , jna-platform-4.5.1 jar包 JNA全称Java Native Access,是一个建立在经典的JNI技术之上的Java开源框架(https://github.com/twall/jna)。JNA提供一组Java工具类用于在运行期动态...

    jna-4.3.0-API文档-中文版.zip

    赠送jar包:jna-4.3.0.jar; 赠送原API文档:jna-4.3.0-javadoc.jar; 赠送源代码:jna-4.3.0-sources.jar; 赠送Maven依赖信息文件:jna-4.3.0.pom; 包含翻译后的API文档:jna-4.3.0-javadoc-API文档-中文(简体)版...

    jna-4.1.0-API文档-中文版.zip

    赠送jar包:jna-4.1.0.jar; 赠送原API文档:jna-4.1.0-javadoc.jar; 赠送源代码:jna-4.1.0-sources.jar; 赠送Maven依赖信息文件:jna-4.1.0.pom; 包含翻译后的API文档:jna-4.1.0-javadoc-API文档-中文(简体)版...

    jna-5.5.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-5.4.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-4.5.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-5.0.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-4.0.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-4.5.2.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-4.4.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-5.10.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-5.6.0.jar中文文档.zip

    # 【jna-***.jar中文文档.zip】 中包含: 中文文档:【jna-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【jna-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【jna-***.jar Maven依赖...

    jna-4.2.2 官方原版下载

    Most simple questions will be answered on the list, but more complicated work, new features or target platforms can be negotiated with any of the JNA developers (this is how several of JNA's features...

    jna-platform-5.10.0-API文档-中英对照版.zip

    赠送jar包:jna-platform-5.10.0.jar; 赠送原API文档:jna-platform-5.10.0-javadoc.jar; 赠送源代码:jna-platform-5.10.0-sources.jar; 赠送Maven依赖信息文件:jna-platform-5.10.0.pom; 包含翻译后的API文档...

    JNA最新源文件jar包

    JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。使用JNI调用共享类库(.dll/.so文件)是非常麻烦的事情,既需要编写java代码,又要编写C语言的代理...

    JNA-5.7.0 jna-platform-5.7.0

    JNA-5.7.0 jna-platform-5.7.0

    jna-5.5.0-API文档-中英对照版.zip

    赠送jar包:jna-5.5.0.jar 赠送原API文档:jna-5.5.0-javadoc.jar 赠送源代码:jna-5.5.0-sources.jar 包含翻译后的API文档:jna-5.5.0-javadoc-API文档-中文(简体)-英语-对照版.zip 对应Maven信息:groupId:...

    jna.rar_ jna win32-x86.jar_function java_jna examples.jar_jna.ja

    JNA(Java Native Access )提供一组Java工具类用于在运行期动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与...

    jna-5.9.0.jar

    2021 最新JNA jar包,jna-5.9.0

    jna-3.5.2jar

    JNA(JavaNativeAccess)框架是一个开源的Java框架,是SUN公司主导开发的,建立在 经典的JNI的基础之上的一个框架。 JNA项目地址:https://jna.dev.java.net/ JNA使Java调用原生函数就像.NET上的P/Invoke一样方便、...

Global site tag (gtag.js) - Google Analytics