`
xuyuanshuaaa
  • 浏览: 393818 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

java JNI的使用

阅读更多
JAVA本地接口(JNI),是JAVA比较特殊的课题,因为JAVA本地接口(JNI)设计不只是JAVA语言设计,它还是JAVA与C或C++程序设计语言结合的课题.

      通常来说一般会在如下情况使用JNI技术:

      1,应用需要调用JAVA语言不支持的依赖于系统平台的特性.

      2,为了整合一些遗留下来的非JAVA语言开发的系统.

      3,为了创建节省时间的应用,不得不采用低级语言.然后通过JAVA调用.
JNI实现了java和c,c++ ,汇编等语言的双向调用。

简单的例子:

JAVA:
Employee中的一个本地方法native   showSalary();
class Employee {

      [color=red]public native void showSalary();[/color]

      static {

            System.loadLibrary("Employee"); // c/c++语言的库文件,windows用dll,linux/unix用.so文件,本例中是Employee.dll文件
该文件必须放在java应用可以找到的路径下,windows下一般放在Windows/System下,这样java应用就可以装载这个库文件了。

      }

      public static void main(String[] args) {

            (new Employee()).showSalary();

      }

}


C

头文件:*.h

      JNI对于本地方法的声明格式有特殊要求,但是JAVA提供了一个非常好用的工具,操作如下:

      >javac Employee.java // 得到class文件

      >javah Employee      // 为Employee.class文件生成对应的Employee.h

生成文件大致如下(省略一些注释和没用的代码,熟悉c语言的人应该很容易看懂):

#include <jni.h> //该文件存在于jdk厂商提供的jdk安装包内,通常位于安装目录include目录下

#ifndef _Included_Employee

#define _Included_Employee

#ifdef   __cplusplus

extern "C" {

#endif

JNIEXPORT void JNICALL Java_Employee_showSalary(JNIEnv*,jobject);
//这个方法就是本地方法的声明部分,本地方法在c语言端的声明
#ifdef    __cplusplus

}

#endif

#endif

创建c语言的主文件:
创建*.c文件:
#include <jni.h>

#include "Employee.h"

#include <stdio.h>

JNIEXPORT void JNICALL Java_Employee_showSalary(JNIEnv* env, jobject obj){

      printf("HELLO WORLD");

      return;

}

编译成库:
之后放入指定的文件夹就可以被引用到了。
windows :cl -Ic:\java\include -Ic:\java\include\win32 -LD Employee.c -F employee

linux       :gcc -shared -i$JDK_HOME/include -I/usr/include Employee.c -o libemployee.co

UNIX/Solaris:cc -G -I/usr/local/java/include -I/usr/local/java/include/solaris Employee.c -o libemployee.so

执行:

将库文件放入系统目录,WINDOWS为WINNT/System32,linux/unix为LD_LIBRARY_PATH,也可以设置系统路径

setenv LD_LIBRARY_PATH /*.so路径/:$LD_LIBRARY_PATH

>java -cp . Employee

JNI技术中数据类型与处理方法

在jni.h文件中定义有对访问对象实例函数与用来访问对象实例属性的方法.GetXXXField/GetStaticXXXField用来获取相应变量域的值和静态域的值,还有对应的用来设置值的函数SetXXXField/SetStaticXXXField函数.除了对域访问的函数以外还有对应的访问方法的函数一般格式如下CallXXXMethod/CallStaticXXXMethod,其中XXX代表访问类型.由于函数众多不一一介绍,具体定义都在jni.h文件里

访问JNI本地数据类型的方法

      如下:

      JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv* env, jobject obj, jstring prompt) {

            char buff[128];

            const char *str = (*env)->GetStringUTFChars(env, prompt,0); //从java获取数据

            printf("%s",str);

            (*env)->ReleaseStringUTFChars(env,prompt,str); //释放资源

           scanf("%s\n",buff);

            return (*env)->NewStringUTF(env,buff); // 返回jstring类型

       }

使用JNIEnv接口指针:

      本地方法中使用JAVA对象,例如String,都要通过本地环境接口指针来完成,如上例.而且他本身也是调用函数的第一个参数.

在JNI本地方法中访问数组:

      JNIEXPORT jint JNICALL Java_IntArray_releaseArray(JNIEnv *env, jobject obj, jintArray arr){

      ...

      int i;

       int sum = 0;

      jsize len = (*env)->GetArrayLength(env,arr);

      jint *body = (*env)->GetFloatArrayElements(env,arr,0);

      for (i=0;i<len;i++){ sum+= body[i];}

      (*env)->ReleaseIntArrayElements(env,arr,body,0);

      return sum;

      }

当然也有对应于不同基本类型数组的模版函数Get<type>ArrayElements/Release<type>ArrayElements,但是如果是一个非常巨大的数组的话,也要一次取全部数组?这样会有很大的内存消耗的.JNI因此也提供了一个可以指定读取某一处元素的函数Get/Set<type>ArratRegin();

当元素为一个对象的时候可以使用GetObjectArrayElement()/SetObjectArrayElement()来取和更新指定元素.

JNI中的主要技术:

局部引用与全局引用

由于JNI一般情况下将为JAVA对象创建一个本地引用,这是因为本地引用可以保证被JAVA虚拟机最终在系统中释放,归还系统资源,当程序在那个创建局部引用的本地方法中执行了返回操作后,这个局部引用也就无效了.因此应该避免如下写法:

static jclass cls = 0;

JNIEXPORT void JNICALL Java_FieldAccess_accessFields(JNIEnv* env, jobject obj) {

      cls = (*env)->GetObjectClass(env,obj);

      ......

}

当第二次调用该函数的时候,由于cls指向的引用已经失效,所以会引起错误.正确的方法是:

static jclass cls = 0;

JNIEXPORT void JNICALL Java_FieldAccess_accessFields(JNIEnv* env, jobject obj) {

      jclass clsTmp = (*env)->GetObjectClass(env,obj);

      clsTmp= (*env)->NewGlobalRef(env,cls1);

      ......

}

这样这个引用对象会一直存在,当不在使用的时候会自动被JVM回收或直到调用函数DeleteGlobalRef(),所以要记得用完后释放该全局引用对象.但是当创建大量局部引用,或者大数据量对象的时候,为了避免局部引用表溢出,需要显式调用DeleteGlobalRef(),

处理本地方法引起的JAVA错误:

...

(*env)->ExceptionDescribe(env); // 输出一些调试信息

(*env)->ExceptionClear(env);      // 清除以前的异常信息

jthrowable newExceCls = (*env)->FindClass(env,"java/lang/IllegalArgumentException");

if(newExceCls==0) return ;

(*env)->ThrowNew(env,newExecCls,"thrown from c code"); //如果存在异常,抛出交由JAVA端处理.

...

当然也可以使用ExceptionOccurred()

...

jthrowable cls = (*env)->ExceptionOccurred(env);

if(cls != 0) (*env)->ThrowNew(env,cls ,"thrown from c code");

线程与本地方法

      1,JNI接口指针JNIEnv*仅在当前线程有效,不能传递或者保留到全局引用中以备后用.

      2,绝对不可以将一个局部引用从一个线程传递给另一个线程.

      3,合理仔细使用全局变量.

本地方法的线程同步

...

(*env)->MonitorEnter(env,obj);

...//同步代码

(*env)->MonitorExit(env,obj);

...
分享到:
评论

相关推荐

    java jni 传递结构体

    文档里描述了如何通过jni方法在java与c++代码之间传递非基本类型数据

    java jni简单实例

    2. **头文件生成**:在使用JNI前,我们需要为每个本地方法生成对应的C/C++头文件,这通常通过`javah`工具完成。这个头文件包含了Java类和方法的定义,以及JNI所需的函数原型。 3. **本地方法实现**:在生成的头文件...

    Java JNI调用IC卡读卡器

    Java JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在很多情况下被用来调用本地库,比如C、C++编写的库,这在处理特定硬件设备或者高性能计算时非常有用。在...

    JAVA通过JNI调用C#dll的整个项目工程

    Java通过JNI调用C# DLL是一个跨平台、跨语言的技术实践,主要应用于需要利用Java的稳定性和C#的高性能场景。JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。C# ...

    JAVA JNI C++调用示例

    Java Native Interface (JNI) 是Java平台提供的一种标准方式,允许Java代码和其他语言写的代码进行交互。在本示例中,我们将探讨如何通过JNI在Java中调用C++代码,并最终打包成可执行的JAR包。 首先,让我们理解...

    JNI 调用实例(java JNI cpp互相调用实例)

    通过本文,我们可以了解 Java 和 C++ 之间的互相调用实例的实现过程,包括 C++ DLL 文件的创建和使用,以及 Java 代码中使用 JNI 技术调用 C++ DLL 文件的实现细节。这种技术可以应用于需要 Java 和 C++ 之间互相...

    Android C、Java、JNI效率测试结果.doc

    Android 操作系统中,效率测试是一个非常重要的方面,特别是在使用 JNI(Java Native Interface)调用 C 语言时。这个文档描述了 Android G1 环境中,C、Java、JNI 调用(C 调 Java、Java 调 C)基本运算、方法调用...

    java jni教程

    - 使用JNI可以利用C/C++的高性能特性,但需要注意过度使用JNI可能导致性能下降,因为Java和本地代码之间的切换有额外开销。 - 适当选择哪些部分代码用JNI实现,如性能敏感的计算或调用操作系统API。 通过深入学习...

    JAVA JNI调用DLL完整步骤

    在某些场景下,比如调用操作系统特定的功能或者利用已有的C/C++库,我们需要使用JNI来实现Java与本地代码(如DLL动态链接库)的交互。本教程将详细介绍如何通过JNI在Java中调用DLL的完整步骤。 1. **创建Java类和...

    JAVAjni全部代码

    在本主题“JAVAjni全部代码”中,我们聚焦于如何在Java程序中使用JNI来创建和操作ini配置文件。 首先,我们需要理解JavaJNI的工作原理。JNI允许Java代码通过`System.loadLibrary()`方法加载本地库(.dll on Windows...

    Java再说JNI之实例

    Java再次探讨JNI(Java Native Interface)这一主题,其主要目的是为了解决Java语言与本地代码交互的问题。...通过学习这些实例,开发者可以进一步提升在Java中使用JNI的能力,解决特定问题并提升程序性能。

    Java JNI调用动态库(Linux、Windows)的实现步骤

    ### Java JNI调用动态库(Linux、Windows)的实现步骤 #### 一、概述 Java Native Interface (JNI) 是一种标准的 Java 接口,它允许 Java 代码和其他语言(如 C 或 C++)编写的代码进行交互。通过 JNI,Java 应用...

    Java jni调用c实例

    Java JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下被使用,比如优化性能、利用已有的C/C++库或者访问操作系统特定的功能。在这个"Java jni调用...

    JAVA中jni使用

    Java中的JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下都是必要的,比如调用现有的C/C++库、提高性能的关键算法实现、或者利用硬件特性等。这篇...

    Java JNI 编程进阶

    - 使用JNI的开发流程通常包括编写Java代码、生成JNI头文件、编写本地代码实现、编译本地代码并生成库文件、最后在Java中加载库文件并调用本地方法。 总之,Java JNI编程进阶涉及到性能优化、本地系统接口调用和...

    java高级jni教程

    Java高级JNI教程主要探讨了Java Native Interface(JNI)这一技术,它是Java平台中用于与本地代码交互的重要工具。JNI允许Java程序调用C/C++编写的库,反之亦然,从而实现了Java应用与操作系统底层功能的深度融合。...

    Java中使用Jni简单示例过程

    ### Java与JNI交互详解:基于“Java中使用Jni简单示例过程”的深入解析 #### 核心概念:Java Native Interface (JNI) Java Native Interface(JNI)是Java平台标准的一部分,它允许Java代码与其他语言(如C或C++)...

    java jni c++代码

    在这个主题中,我们将深入探讨Java JNI与Visual Studio 2010 C++代码的结合使用。 首先,我们需要理解JNI的基本概念。JNI提供了一套接口,让Java虚拟机(JVM)能够调用本地方法,即非Java编写的函数。这些本地方法...

    java的JNI本地方法介绍大全

    3. **优化性能**:对于时间敏感的代码片段,如图形处理或高性能计算,底层语言如C++可能会提供更好的性能,因此可以使用JNI在Java中调用这些代码。 **书写步骤** 1. **编写Java类**:首先定义一个Java类,其中包含...

    NDK编译 JAVA JNI 原生调用

    JNI(Java Native Interface)是Java平台的一个重要特性,它允许Java代码和其他语言写的代码进行交互。在Android开发中,NDK(Native Development Kit)则是一个工具集,它允许开发者使用C/C++编写部分应用程序,以...

Global site tag (gtag.js) - Google Analytics