本文是《Java Native Interface Programmer's Guide and Specification》的读书笔记

Java Native Interface可以让编程人员在Java里调用其他语言编写的方法,来弥补Java运行效率低下的缺点;

jni可以用来做什么?:

  • 在Java应用中使用本地编程语言如c/c++编写的代码;
  • 将Java虚拟机融入到由C/c++编写的的应用中;
  • 实现一个Java虚拟机;
  • 从技术层面理解语言的互操作性,特别是垃圾收集机制和多线程实现机制;

jni支持两种的本地代码:本地链接库和本地应用;

  • 使用jni在本地链接库中编写可以让Java应用调用的本地方法(native methods),Java应用可以像调用Java编写的方法一样调用本地方法(本地方法是由其他语言编写的,如C/C++);
  • jni允许调用接口(invocation interface),在本地应用中嵌入Java虚拟机(java virtual mathine),本地应用可以调用实现了Java虚拟机的本地链接库,然后就可以调用接口来执行Java编写的组件;

使用jni的步骤为:

  1. 创建一个java Class(如HelloWorld.java),在里面声明本地方法;
  2. 使用javac 命令编译源文件(HelloWorld.java),这个命令会在当前目录下生成一个HelloWorld.class文件;
  3. 使用命令:javah -jni 来生成一个C的头文件(HelloWord.h),头文件里包含本地方法实现的原型;
  4. 用C语言编写本地方法的实现(HelloWorld.c);
  5. 使用宿主环境的C编译器和链接器将本地方法的实现的文件(HelloWorld.c)编译为本地链接库(HelloWorld.dll 或者libHelloWorld.so);
  6. 运行HelloWorld的程序,类文件(HelloWorld.class)和链接库(HelloWorld.dll或者libHelloWorld.so)都会在运行时加载;

下面以一个HelloWorld的例子来掌握使用jni编程的步骤:

本地方法的声明:

class HelloWorld {
/**本地方法的声明与普通的Java方法的声明区别就是多一个native的修饰
**/
private native void print();//本地方法
private void doSomething(){};//普通Java方法
public static void main(String[] args) {
new HelloWorld().print();
}
static {
/**HelloWorld是链接库的名字,为了保证这个方法可以成功调用,必须创建好这个链接库(HelloWorld.dll在Win32里,libHelloWorld.so在Solaris中)***/
System.loadLibrary("HelloWorld");
}
}

native关键字表明这个方法是由其他语言实现的,但这个native方法被调用前,实现本地方法的本地链接库必须先被加载;如上面代码所示,在static区域加载这个本地链接库。Java虚拟机会在调用任何方法(本地方法或普通方法)前,自动初始化静态区域,这样就可以保证在调用本地方法时,链接库文件已经加载进来了。

编译原文件:使用命令

javac HelloWorld.java

这个命令执行成功后,会在当前目录下生成一个HelloWorld.class 文件;

生成头文件:使用命令:

 javah -jni HelloWorld

这个命令执行成功后,会生成一个HelloWorld.h的文件,头文件里最重要的就是本地方法的原型,也就是在用其他语言实现的的文件里,这个本地方法是以怎样一个形式出现的。上面的print()本地方法在头文件里的形式为:

JNIEXPORT void JNICALL
Java_HelloWorld_print (JNIEnv *, jobject);

JNIEXPORT和JNICALL是两个宏变量,用来保证可以从本地链接库导出这个本地方法并且C编译器会为这个本地方法生成正确的调用代码(怎样调用这个本地方法),函数名Java_HelloWorld_print,Java表明这是一个Java调用的方法,HelloWorld是原来的对象的名字,print是在Java里声明的方法的名字.我们发现本地方法的实现会包含两个参数,而我们声明本地方法是没有参数的,每一个本地方法的实现的第一个参数就是JNIEnv接口指针(包含所有的本地方法的入口指针),第二个参数是原来对象的引用(HelloWorld对象)类似于C++中的this指针;

实现本地方法:在HelloWorld.c中实现本地方法:

#include <jni.h> //这个头文件里,包含本地代码调用JNI方法的信息,在实现的文件里必须包含这个头文件
#include <stdio.h>//C语言头文件,需要使用里面提供的方法时才需要包含进来
#include "HelloWorld.h"//包含有本地方法原型,实现时,也必须包含进来
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}

在编写完本地方法的实现后,就要将HelloWorld.c编译成本地链接库了,不同的操作系统下生成本地链接库的命令也不一样,在Solaris中,可以使用下面的命令生成本地链接库

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

参数G表明让C编译器生成链接库,而不是一般的Solaris文件;

在Win32中,可以使用下面的命令让C++编译器生成动态链接库(命令需要写在同一行里面):

cl -Ic:\java\include -Ic:\java\include\win32
-MD -LD HelloWorld.c -FeHelloWorld.dll

最后就可以运行HelloWorld应用了,需要注意的是,你必须将链接库的路径让Java虚拟机可以搜索到,不然会找不到链接库,导致程序出错

Java Native Interface 编程系列一的更多相关文章

  1. Java Native Interface 六JNI中的异常

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...

  2. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  3. 【详解】JNI(Java Native Interface)(一)

    前言: 一提到JNI,多数编程者会下意识地感受到一种无法言喻的恐惧.它给人的第一感觉就是"难",因为它不是单纯地在JVM环境内操作Java代码,而是跳出虚拟机与其他编程语言进行交互 ...

  4. Java Native Interface Specification Contents 翻译

    https://docs.oracle.com/en/java/javase/12/docs/specs/jni/index.html Google翻译 第1章:简介 本章介绍Java Native ...

  5. JNI(Java Native Interface)

    一.JNI(Java Native Interface)        1.什么是JNI:               JNI(Java Native Interface):java本地开发接口   ...

  6. +Java中的native关键字浅析(Java+Native+Interface)++

    JNI是Java Native Interface的 缩写.从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的 ...

  7. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  8. Java Native Interface 五 JNI里的多线程与JNI方法的注册

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...

  9. Java Native Interface 四--JNI中引用类型

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI支持将类实例和数组类型(如jobjec ...

随机推荐

  1. nginx下目录浏览及其验证功能配置记录

    工作中常常有写不能有网页下载东西的需求,在Apache下搭建完成后直接导入文件即可达到下载/显示文件的效果;而Nginx的目录列表功能默认是关闭的,如果需要打开Nginx的目录列表功能,需要手动配置, ...

  2. PHP用法

    链接: php编写app接口(一)-JSON方式封装接口数据方法 php 非常有用的高级函数PATH_SEPARATOR常量和set_include_path date_default_timezon ...

  3. oracle基本操作符/运算符/操作语言

    racle中的操作符算术操作符: 无论是在sqlserver,或者是java中,每种语言它都有算术操作符,大同小异.Oracle中算术操作符(+)(-)(*)(/) 值得注意的是:/ 在oracle中 ...

  4. BZOJ 4548 小奇的糖果

    Description 有 \(N\) 个彩色糖果在平面上.小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果.求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色. Input 包含 ...

  5. Python-06-面向对象(基础篇)

    面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机 ...

  6. 集合和String

    集合 Collection 接口 |-List 接口 |-LinkedList 类 |-ArrayList 类 |-Set 接口 |-HashSet 类 |-TreeSet 类 |-LinkedHas ...

  7. 高性能JavaScript 编程实践

    前言 最近在翻<高性能JavaScript>这本书(2010年版 丁琛译),感觉可能是因为浏览器引擎的改进或是其他原因,书中有些原本能提高性能的代码在最新的浏览器中已经失效.但是有些章节的 ...

  8. Jquery easy ui datagrid動態加載列問題

    1.如下图效果是当选择不同的日期范围时datagrid则会加载出对应的列数

  9. 跟我从零基础学习Unity3D开发--U3d脚本注意事项及两个基本函数的简单介绍

    经过上一篇的学习,我相信开发环境您已经搭好了,如果还没有搭好可以百度一下. 今天主要讲的有以下几点: 第一:Unity3D中的C#脚本与.net中的C#写法的区别 1.Unity3D C#脚本不支持命 ...

  10. FFT

    void FFT(complex a[],int n,int fl){ ,j=n/;i<n;i++){ if (i<j) {complex t=a[i];a[i]=a[j];a[j]=t; ...