- 浏览: 393818 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
surpassno:
南冠楚囚 写道如果是复制一个一位数组,那么改变复制后的数组并不 ...
java的system.arraycopy()方法 -
南冠楚囚:
如果是复制一个一位数组,那么改变复制后的数组并不影响原数组。你 ...
java的system.arraycopy()方法 -
wxq5513866:
有密码,大家不要下载了,下载也解压不了,别上当了
android中调用webservice -
wxq5513866:
happyhan 写道还要密码啊 能否告知密码
android中调用webservice -
happyhan:
还要密码啊 能否告知密码
android中调用webservice
JAVA本地接口(JNI),是JAVA比较特殊的课题,因为JAVA本地接口(JNI)设计不只是JAVA语言设计,它还是JAVA与C或C++程序设计语言结合的课题.
通常来说一般会在如下情况使用JNI技术:
1,应用需要调用JAVA语言不支持的依赖于系统平台的特性.
2,为了整合一些遗留下来的非JAVA语言开发的系统.
3,为了创建节省时间的应用,不得不采用低级语言.然后通过JAVA调用.
JNI实现了java和c,c++ ,汇编等语言的双向调用。
简单的例子:
JAVA:
Employee中的一个本地方法native 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文件:
编译成库:
之后放入指定的文件夹就可以被引用到了。
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);
...
通常来说一般会在如下情况使用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);
...
发表评论
-
jmx介绍
2012-05-18 15:21 1316"JMX(Java Management Exten ... -
RMI介绍
2012-05-18 09:55 1054Java RMI (Remote Method Invocat ... -
java多线程文件下载
2012-03-08 20:03 24601、DownloadManager类 import java. ... -
java异常处理
2011-11-30 15:27 980public class test { /** ... -
快排和插入排序
2011-10-20 17:08 1144public class CombineQuickSortIn ... -
java NIO
2011-10-09 19:22 1447一、NIO的出现 NIO是JDK1.4里面才出 ... -
java 远程通信协议
2011-10-09 16:55 1580Java 远程通讯可选技术及原理 在分布式服务框架中,一个最基 ... -
system.exit
2011-09-29 17:00 1018System.exit()用来结束当前运行的java虚拟机,参 ... -
java 文件读取方法
2011-09-27 14:50 12191、按字节读取文件内容 2、按字符读取文件内容 3、按行读取文 ... -
timestamp时间戳
2011-09-05 09:51 1225timestamp是一种时间类型 精度很高,比datetim ... -
java 动态代理类的实现,原理及应用
2011-09-03 11:02 2185在目前的Java开发包中包含了对动态代理的支持,但是其实现只支 ... -
java annotation 介绍
2011-09-02 11:03 949元数据的作用 如果要 ... -
java 反射
2011-08-20 11:27 794JAVA语言中的反射机制: 在Java 运行时 环境中 ... -
junit使用
2011-08-05 16:41 1160测试分类:白箱测试、黑箱测试、单元测试、集成测试、功能测试.. ... -
ThreadLocal 知识
2011-08-05 13:58 841ThreadLocal是什么 早在JD ... -
httpclient 介绍
2011-07-28 09:33 10441.HttpClient简介 HttpCl ... -
java解析xml的四种方法
2011-07-13 22:52 14511. DOM(Document Object Model) ... -
xml字符串转化为规则格式的xml字符串
2011-07-13 18:53 1389import java.io.ByteAr ... -
java中的参数传递
2011-07-13 10:48 983面试题:当一个对象被当 ... -
StringUtils的实用方法
2011-07-13 10:16 1700tringUtils 方法的操作对象是 java.lang. ...
相关推荐
文档里描述了如何通过jni方法在java与c++代码之间传递非基本类型数据
2. **头文件生成**:在使用JNI前,我们需要为每个本地方法生成对应的C/C++头文件,这通常通过`javah`工具完成。这个头文件包含了Java类和方法的定义,以及JNI所需的函数原型。 3. **本地方法实现**:在生成的头文件...
Java JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在很多情况下被用来调用本地库,比如C、C++编写的库,这在处理特定硬件设备或者高性能计算时非常有用。在...
Java通过JNI调用C# DLL是一个跨平台、跨语言的技术实践,主要应用于需要利用Java的稳定性和C#的高性能场景。JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。C# ...
Java Native Interface (JNI) 是Java平台提供的一种标准方式,允许Java代码和其他语言写的代码进行交互。在本示例中,我们将探讨如何通过JNI在Java中调用C++代码,并最终打包成可执行的JAR包。 首先,让我们理解...
通过本文,我们可以了解 Java 和 C++ 之间的互相调用实例的实现过程,包括 C++ DLL 文件的创建和使用,以及 Java 代码中使用 JNI 技术调用 C++ DLL 文件的实现细节。这种技术可以应用于需要 Java 和 C++ 之间互相...
Android 操作系统中,效率测试是一个非常重要的方面,特别是在使用 JNI(Java Native Interface)调用 C 语言时。这个文档描述了 Android G1 环境中,C、Java、JNI 调用(C 调 Java、Java 调 C)基本运算、方法调用...
- 使用JNI可以利用C/C++的高性能特性,但需要注意过度使用JNI可能导致性能下降,因为Java和本地代码之间的切换有额外开销。 - 适当选择哪些部分代码用JNI实现,如性能敏感的计算或调用操作系统API。 通过深入学习...
在某些场景下,比如调用操作系统特定的功能或者利用已有的C/C++库,我们需要使用JNI来实现Java与本地代码(如DLL动态链接库)的交互。本教程将详细介绍如何通过JNI在Java中调用DLL的完整步骤。 1. **创建Java类和...
在本主题“JAVAjni全部代码”中,我们聚焦于如何在Java程序中使用JNI来创建和操作ini配置文件。 首先,我们需要理解JavaJNI的工作原理。JNI允许Java代码通过`System.loadLibrary()`方法加载本地库(.dll on Windows...
Java再次探讨JNI(Java Native Interface)这一主题,其主要目的是为了解决Java语言与本地代码交互的问题。...通过学习这些实例,开发者可以进一步提升在Java中使用JNI的能力,解决特定问题并提升程序性能。
### Java JNI调用动态库(Linux、Windows)的实现步骤 #### 一、概述 Java Native Interface (JNI) 是一种标准的 Java 接口,它允许 Java 代码和其他语言(如 C 或 C++)编写的代码进行交互。通过 JNI,Java 应用...
Java JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下被使用,比如优化性能、利用已有的C/C++库或者访问操作系统特定的功能。在这个"Java jni调用...
Java中的JNI(Java Native Interface)是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下都是必要的,比如调用现有的C/C++库、提高性能的关键算法实现、或者利用硬件特性等。这篇...
- 使用JNI的开发流程通常包括编写Java代码、生成JNI头文件、编写本地代码实现、编译本地代码并生成库文件、最后在Java中加载库文件并调用本地方法。 总之,Java JNI编程进阶涉及到性能优化、本地系统接口调用和...
Java高级JNI教程主要探讨了Java Native Interface(JNI)这一技术,它是Java平台中用于与本地代码交互的重要工具。JNI允许Java程序调用C/C++编写的库,反之亦然,从而实现了Java应用与操作系统底层功能的深度融合。...
### Java与JNI交互详解:基于“Java中使用Jni简单示例过程”的深入解析 #### 核心概念:Java Native Interface (JNI) Java Native Interface(JNI)是Java平台标准的一部分,它允许Java代码与其他语言(如C或C++)...
在这个主题中,我们将深入探讨Java JNI与Visual Studio 2010 C++代码的结合使用。 首先,我们需要理解JNI的基本概念。JNI提供了一套接口,让Java虚拟机(JVM)能够调用本地方法,即非Java编写的函数。这些本地方法...
3. **优化性能**:对于时间敏感的代码片段,如图形处理或高性能计算,底层语言如C++可能会提供更好的性能,因此可以使用JNI在Java中调用这些代码。 **书写步骤** 1. **编写Java类**:首先定义一个Java类,其中包含...
JNI(Java Native Interface)是Java平台的一个重要特性,它允许Java代码和其他语言写的代码进行交互。在Android开发中,NDK(Native Development Kit)则是一个工具集,它允许开发者使用C/C++编写部分应用程序,以...