JNI-Linux

JNI是Java Native Interface的缩写,Java源生接口/本地调用/本地接口,允许Java和其他语言代码进行互相调用,Java可以调用C/C++代码,C/C++也可以调用Java的。Java程序运行在JVM上,所以平台无关,但通过JNI调用原生代码C/C++就会丧失这个特性,破坏可移植性,至少原生代码部分总是需要重新编译的。但是一下情况是可以接受的。

1.使用一些旧的库

2.与硬件、操作系统进行交互

3.为了提高程序的性能

Note:jni.h就在%JAVA_HOME%\include下,还有%JAVA_HOME%\include\win32下的jni_md.h

Warning:javah在Java10,生成C/C++头文件的功能由javac -h代替

image

编写JAVA类

static代码段的System.load调用,这段代码表示在程序加载的时候,自动加载libHello.so库。
区分一下加载动态库的2种方式
一个概念是JVM有两个重要变量java.class.pathjava.library.path。前者指明了package的路径,后者指明了动态链接库的路径。
System.load();绝对路径
System.loadLibrary ();java.library.path下加载,不需要指明扩展名

public class Hello{

   public native static String sayHello(String name);

   static{
           System.load("/usr/project/test/libHello.so");
         #System.loadLibrary("Hello");
     }

    public static void main(String[] args){
             Hello hello = new Hello();
             String ret = hello.sayHello("Simona");
             System.out.println(ret);
   }
 }

编译JAVA类

javac Hello.java

生成Hello.h

javah -jni Hello
or
javac -h . Hello
Note:JAVA 10弃用了javah

有包名的情况下需要指定classpath,不然会出现UnsatisfiledLinkError

javah -classpath 'your package path' -jni 'package'.Hello
or
指明共享库路径
java -Djava.library.path=. Hello
export LD_LIBRARY_PATH=“Hello路径”:$LD_LIBRARY_PATH

编写Native Method

生成的Hello.h的头文件带有需要实现的Native Method,实现这个Native Method需要指定参数名称
cat Hello.h
vim hello.c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */

#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Hello
 * Method:    sayHello
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_Hello_sayHello
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif
#include <stdio.h>
#include "Hello.h"

JNIEXPORT jstring JNICALL Java_Hello_sayHello(JNIEnv *env, jclass jc, jstring name)
{
    const char *buf;

    buf = (*env)->GetStringUTFChars(env, name, NULL);
    if (NULL == buf)
    {
        return NULL;
    }

    printf("%s\n", buf);
    
    (*env)->ReleaseStringUTFChars(env, name, buf);

    return (*env)->NewStringUTF(env, "hello");
}

GetStringUTFChars
返回指向字符串的 UTF-8 字符数组的指针,如果不能创建这个字符数组,返回 null。该数组在被ReleaseStringUTFChars()释放前将一直有效
const char* GetStringUTFChars(jstring string,jboolean* isCopy)

NewStringUTF
利用UTF-8字符数组构造新java.lang.String对象
(*env)->NewStringUTF(env, "hello");

制作动态库

由于是Linux平台,需要制作后缀是.so的动态库,其中,需要指定jni.h的路径,必要时还需要jni_md.h的路径,该文件在jdk的目录中。这里指定了jni.h和jni_md.h的路径。
一个库的必须要是:lib+库名+.so。链接的时候只需要提供库名就可以了

find / -name jni.h
/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.221-2.6.18.0.el7_6.x86_64/include/jni.h
find / -name jni_md.h
/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.221-2.6.18.0.el7_6.x86_64/include/linux/jni_md.h

gcc -c -fPIC -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.221-2.6.18.0.el7_6.x86_64/include/ -I/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.221-2.6.18.0.el7_6.x86_64/include/linux/ Hello.c -o Hello.o

gcc -shared Hello.o -o libHello.so

调用动态库

java Hello
Simona
hello

出现UnsatisfiedLinkError

pwd
/usr/project/test

export LD_LIBRARY_PATH=/usr/project/test:$LD_LIBRARY_PATH
java Hello
Simona
hello

or

java -Djava.library.path=. Hello
Simona
hello

创建调用类

import java.util.*;
public class HelloJni
{
     public static void main(String argv[])
     {
         System.out.println( System.getProperty("java.library.path"));
         new HelloJni();
     }

     public HelloJni()
     {
         new Hello().sayHello("Hello,Jni !"); //调用Hello的原生函数sayHello
     }
}

执行调用

javac HelloJni.java
java HelloJni
/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Hello,Jni !

参考网址

JNI编程实现(Linux)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • _ 声明: 对原文格式以及内容做了细微的修改和美化, 主要为了方便阅读和理解 _ 一. 基础 Java Nativ...
    元亨利贞o阅读 6,001评论 0 34
  • *** 说明:本文不代表博主观点,均是由以下资料整理的读书笔记。 *** 【参考资料】 1、向您的Android ...
    莫绪旻_向屿阅读 1,719评论 0 6
  • JNI是什么? JNI的全称就是Java Native Interface,顾名思义,就是Java和C/C++相互...
    hongzhenw阅读 3,602评论 2 15
  • 我是一名普通的人民教师,今天是9月10日——我们的节日。在这个特殊的日子里,我不禁在思考这个节日的价值、意义之所在...
    Joanne_fa80阅读 356评论 0 4
  • 在大漠先生的引领下,我开始了一周碧珠生活智慧的禅绕画之旅,今天做一个小总结。 在这次的小结里,我将大漠先生的智慧语...
    时光分拣机阅读 980评论 1 19