zoukankan      html  css  js  c++  java
  • Java 调用底层接口的几种方法

    Java 调用底层接口

    Java 调用底层接口要通过动态链接库进行,在windows下是dll文件,linux是so文件

    Java调用动态库所需要关心的问题:

    •     如何装载文件,以及如何定位所要使用的方法;
    •      数据类型是如何对应的;
    •     如何给使用的方法传递参数;
    •     如何获取返回的值。

    目前调用底层接口用的比较多的技术包括jni、jna、jnative、Nativecall等

    JNI 封装本地接口

    JAVA可以通过JNI接口访问本地的动态连接库,从而扩展JAVA的功能。使用JAVA JNI接口主要包括以下步骤:

    ²  编写JAVA代码,注明要访问的本地动态连接库和本地方法;

    ²  编译JAVA代码得到.class文件;

    ²  使用javah -jni 生成该类对应的C语言.h文件;

    ²  使用C/C++实现(3)生成的.h文件中声明的各函数;

    ²  编译C/C++实现代码生成动态连接库。
    本文使用一个简单的helloWorld示例演示JNI的使用。

    编写JAVA代码

    View Code
    1 public class helloWorld
    2
    3 {
    4
    5 public native void SayHello(String name);
    6
    7
    8
    9 static
    10
    11 {
    12
    13 System.loadLibrary("jniHelloworld");
    14
    15 }
    16
    17
    18
    19 public static void main(String [] argv)
    20
    21 {
    22
    23 helloWorld hello = new helloWorld();
    24
    25 hello.SayHello("world ");
    26
    27 }
    28 }


    编译JAVA代码

    javac helloWorld.java


    生成实现函数头文件


    javah -classpath . helloWorld

    得到的helloWorld.h文件内容如下:

    View Code
    1 /* DO NOT EDIT THIS FILE - it is machine generated */
    2
    3 #include <jni.h>
    4
    5  /* Header for class helloWorld */
    6
    7
    8
    9 #ifndef _Included_helloWorld
    10
    11  #define _Included_helloWorld
    12
    13 #ifdef __cplusplus
    14
    15  extern "C" {
    16
    17  #endif
    18
    19  /*
    20
    21 * Class: helloWorld
    22
    23 * Method: SayHello
    24
    25 * Signature: (Ljava/lang/String;)V
    26
    27 */
    28
    29 JNIEXPORT void JNICALL Java_helloWorld_SayHello
    30
    31 (JNIEnv *, jobject, jstring);
    32
    33
    34
    35 #ifdef __cplusplus
    36
    37 }
    38
    39  #endif
    40
    41  #endif

     

     

    在VS中创建工程并实现该函数

    View Code
    1 #include "helloWorld.h"
    2
    3 #include <stdio.h>
    4
    5 #include <string.h>
    6
    7  void JNICALL Java_helloWorld_SayHello(JNIEnv * env, jobject obj, jstring str)
    8
    9 {
    10
    11 jboolean b = true;
    12
    13 char s[80];
    14
    15 memset(s, 0, sizeof(s));
    16
    17 strcpy_s(s ,(char*)env->GetStringUTFChars(str, &b));
    18
    19 printf("Hello, %s", s);
    20
    21 env->ReleaseStringUTFChars(str , NULL);
    22
    23 }


      这是JNI的关键:通过env我们可以使用JAVA提供的一组函数操作与转换函数传递的参数。


    编译VC项目得到动态连接库 helloWorld.dll。

    把工程输出文件的位置设置成helloWorld类所在的目录,编译之前要把jdk的include目录加到工程属性中

    然后在命令行中执行

    Java helloWorld 会输出helloWorld

    JNA封装本地接口

    http://jna.java.net/#demos

     

    View Code
    1 package com.sun.jna.examples;
    2
    3
    4
    5 import com.sun.jna.Library;
    6
    7 import com.sun.jna.Native;
    8
    9 import com.sun.jna.Platform;
    10
    11
    12
    13  /** Simple example of JNA interface mapping and usage. */
    14
    15  public class HelloWorld {
    16
    17
    18
    19 // This is the standard, stable way of mapping, which supports extensive
    20
    21 // customization and mapping of Java to native types.
    22  
    23 public interface CLibrary extends Library {
    24
    25 CLibrary INSTANCE = (CLibrary)
    26
    27 Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
    28
    29 CLibrary.class);
    30
    31
    32
    33 void printf(String format, Object... args);
    34
    35 }
    36
    37
    38
    39 public static void main(String[] args) {
    40
    41 CLibrary.INSTANCE.printf("Hello, World\n");
    42
    43 for (int i=0;i < args.length;i++) {
    44
    45 CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
    46
    47 }
    48
    49 }
    50
    51 }

     

     

    JNA 可以直接调用底层接口,而不用对底层接口进行封装,像例子调用printf一样,底层接口可以通过这种方式直接把接口提供给java调用

    Jnative

    Jnative用法和jna类似,都是借助于开源项目实现对底层接口的调用,但是用法比jna简单一点,不需要在一个java接口中描述目标文件中的函数与结构,用法如下:

    建立test_say.java文件,需要配置好JNative.jar包

     

    View Code
    1 import org.xvolks.jnative.JNative;
    2
    3  import org.xvolks.jnative.Type;
    4
    5  import org.xvolks.jnative.exceptions.NativeException;
    6
    7 import org.xvolks.jnative.pointers.Pointer;
    8
    9 import org.xvolks.jnative.pointers.memory.MemoryBlockFactory;
    10
    11 import org.xvolks.jnative.pointers.memory.NativeMemoryBlock;
    12
    13 import org.xvolks.jnative.util.Callback;
    14
    15 //import org.xvolks.test.callbacks.linux.LinuxCallback;
    16
    17
    18
    19 public class test_ helloWorld {
    20
    21 private final static String LIB_NAME = " msvcrt "; //自动判断.so 或者.dll
    22
    23
    24
    25 public static void main(String[] args) throws NativeException, IllegalAccessException {
    26
    27 try {
    28
    29 JNative printf =new JNative(LIB_NAME," printf ");
    30
    31 printf.setParameter(0,”hello world”);
    32
    33 printf.invoke();
    34
    35 }
    36
    37 catch (Exception e)
    38
    39 {
    40
    41 e.printStackTrace();
    42
    43 }
    44
    45 }
    46
    47 }
  • 相关阅读:
    ValueError:Expected more than 1 value per channel when training, got input size torch.Size([1, 512, 1, 1])
    指定GPU运行
    ModuleNotFoundError: No module named 'past'
    ImportError: libSM.so.6: cannot open shared object file: No such file or dir
    ImportError: libgthread-2.0.so.0: cannot open shared object file: No such file or directory
    zsh: command not found: conda
    TypeError: Class advice impossible in Python3. Use the @implementer class decorator instead.
    数据结构(八)图
    数据结构(二)线性表
    数据结构(七)数与二叉树
  • 原文地址:https://www.cnblogs.com/shapherd/p/1971636.html
Copyright © 2011-2022 走看看