JNI程序规范和指南2——一个简单的例子

这是一个关于JNI的系列文章。

本文通过一个简单的例子来介绍如何使用JNI:一个Java程序调用C代码输出hello world。

概述

下图描述了Java程序调用C代码输出hello world的过程

Steps in Writing and Running the “Hello World” Program

这个过程主要包含以下几个步骤:

  1. 创建一个HelloWorld.java文件声明了本地方法(native method)。
  2. 使用javac编译Java源码,生成.class文件。
  3. 使用javah -jni生成C头文件,这个文件包含了这个本地方法。(native method)的函数原型。
  4. 在HelloWorld.c文件中实现本地方法(native method)。
  5. 使用本地C编译器编译生成本地库文件(.dll后者.so)。
  6. 运行Java程序,.class.dll/.so运行时加载。

声明本地方法(native method)

首先java程序定义了一个HelloWorld的类,包含了一个本地方法print

import java.lang.*;
class HelloWorld{
    private native void print();
    public static void main(String args[]) {
        new HelloWorld().print();
    }
    static{
        System.loadLibrary("HelloWorld");
    }
}

HelloWorld这个类首先定义了本地方法print,然后main函数中实例化HelloWorld并调用print。最后通过System.loadLibrary加载对应的本地库。

声明本地方法必须使用关键字native,然后会在C中实现这个函数。在本地方法被调用之前,必须确保本地库已经被加载,这里我们使用static的方式初始化加载,确保了在调用print之前本地库已被加载。

System.loadLibrary需要一个库名字,为了System.loadLibrary("HelloWorld")能够成功执行,需要在Windows创建HelloWorld.dll或者在Linux中创建libHelloWorld.so

编译HelloWorld类

使用javac HelloWorld.java编译生成.class文件

创建本地方法的C头文件

使用javah -jni HelloWorld生成一个JNI风格的头文件, 然后在HelloWorld.h中会有对应的print函数原型:

JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);

先不管JNIEXPORTJNICALL两个宏。你可能注意到本地方法的C实现有两个形参即使Java代码中并没有任何形参的定义,C的本地方法实现的第一个形参是JNIEnv指针,这里你可以简单的理解为他是一个Java环境的实现,提供了一些接口;第二个形参是一个HelloWorld对象的引用(类似于C++的this指针)。后面会继续讲解他们的用法。

本地方法的实现

你需要根据生成的头文件来实现本地方法:

#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"

JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *env, jobject obj){
      printf("Hello World in C\n");
      return;
  }

编译C源文件并创建一个本地库

不同的操作系统支持不同的库文件,比如Linux支持的.so:

cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so

Windows则需要生成.dll,你需要进入vs的命令行工具(比如VS2015 x64 本机命令工具提示符)执行下列命令(前提是你安装了visual studio和Java环境):

cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD HelloWorld.c -FeHelloWorld.dll  

上面的编译方法中Linux是书中的命令,没有验证过是否能够执行;Windows书中的命令执行不成功,以上是根据我的使用环境修改过后的命令。

运行Java程序

完成上述步骤之后,你就可以执行Java程序了:

java HelloWorld

输出的接口是:

Hello World in C

  • 第一部分,简介和JNI入门

JNI程序规范和指南1——简介
JNI程序规范和指南2——一个简单的例子

  • 第二部分,JNI指南

JNI程序规范和指南3——基本类型, 字符串和数组
JNI程序规范和指南4——字段和方法
JNI程序规范和指南5——JNI中的局部引用和全局引用
JNI程序规范和指南6——异常

  • 第三部分,JNI规范

建议不要用于商业用途, 转载请注明原文地址: https://Soo-Q6.github.io/blog/2019-09-28-JNI-guides-and-specifications-2/


© 2019. All rights reserved.

Powered by shouqin v1.0