在Windows中实现Java本地方法

合集下载

Java桌面应用开发

Java桌面应用开发

优化SQL语句:避免使用复杂的SQL语句, 使用索引和查询优化器
异步处理:将耗时操作异步执行,避免阻 塞主线程
合理使用多线程:根据任务性质合理分配 线程,提高并发处理能力
监控系统资源:CPU、内存、磁盘、网络等 性能优化方法:减少内存占用、优化算法、使用多线程等 工具:JProfiler、VisualVM等 优化效果评估:性能测试、用户反馈等
需求分析:明确应用需求,确定功能模块 设计阶段:设计应用界面和功能模块,制定开 发计划 开发阶段:编写代码,实现功能模块,进行单 元测试
测试阶段:进行集成测试、系统测试和用户验 收测试 部署阶段:将应用部署到目标平台上,进行性 能优化和调试 维护阶段:对应用进行维护和升级,解决用户 反馈的问题
Java桌面应用界面 设计
Java桌面应用开发
作者:
目录
添加章节标题
Java桌面应用开发 基础
Java桌面应用开发简介 Java桌面应用的特点 Java桌面应用开发环境搭建
Java桌面应用开发流程 Java桌面应用开发工具介绍 Java桌面应用开发案例分析
JDK安装:下载并安装JDK,设置JAVA_HOME 环境变量
用户身份验证:确保 用户身份的真实性和 唯一性
安全协议:使用 SSL/TLS等安全协议进 行数据传输和存储
密码管理:要求用户 设置强密码,并定期 更换
异常处理:对用户异 常行为进行监控和报 警
恶意软件类型:病毒、木马、间谍软件等 攻击方式:通过网络、电子邮件、USB设备等传播 防范措施:安装防病毒软件、定期更新系统补丁、提高安全意识等 安全编程:使用安全的编程实践,如输入验证、数据加密等
Java桌面应用功能 实现
文件读取:使 用 FileInputStream 类读取文件内 容

java native方法调用原理

java native方法调用原理

java native方法调用原理Java的Native方法允许在Java代码中调用本地(即非Java虚拟机)中实现的方法。

它们通常用于与操作系统、硬件或C/C++库进行交互。

Native方法调用原理如下:1. 编写本地方法:使用Java的native关键字在Java类中定义一个本地方法,并将其声明为native。

例如:native void myNativeMethod();2. 编译Java类文件:使用javac命令编译Java类文件,生成对应的.class文件。

3. 生成本地方法库:使用javah命令生成一个包含本地方法的C头文件。

例如:javah MyClass,将生成一个名为MyClass.h 的头文件。

4. 实现本地方法:在生成的头文件中实现native方法的具体功能。

例如,在C/C++中实现myNativeMethod()方法。

5. 编译本地方法库:使用C/C++的编译工具将之前实现的本地方法库编译为可执行的库文件。

例如,在Windows上使用GCC编译器编译为.dll文件,在Linux上使用GCC编译器编译为.so文件。

6. 加载本地方法库:在Java代码中使用System.loadLibrary()方法加载已编译的本地方法库。

例如:System.loadLibrary("mylib"),其中mylib是库文件的名称。

7. 调用本地方法:在Java代码中通过调用本地方法来调用实现的本地功能。

例如:myNativeMethod()。

在运行时,Java虚拟机会在调用本地方法时,将该方法的控制权传递给本地方法库,由库文件中对应的方法实现来执行。

执行完成后,Java虚拟机将控制权返回给Java代码继续执行。

需要注意的是,Native方法存在一定的开销,并且对Java的跨平台性有一定影响。

因此,在使用Native方法时,应该谨慎选择并进行性能测试。

java打开本地应用程序(调用cmd)---Runtime用法详解

java打开本地应用程序(调用cmd)---Runtime用法详解

java打开本地应⽤程序(调⽤cmd)---Runtime⽤法详解 有时候我们需要借助java程序打开电脑⾃带的⼀些程序,可以直接打开或者借助cmd命令窗⼝打开⼀些常⽤的应⽤程序或者脚本,在cmd窗⼝执⾏的命令都可以通过这种⽅式运⾏。

例如:package cn.xm.exam.test;import java.io.IOException;import org.junit.Test;public class TestCmd {@Testpublic void test1() throws IOException {// 直接打开应⽤程序Runtime.getRuntime().exec("C:/Users/liqiang/Desktop/开机后点它.bat"); // 打开⼀个批处理⽂件Runtime.getRuntime().exec("E:/酷狗/KGMusic/KuGou.exe"); // 打开酷狗/******** 可以通过cmd命令打开软件或者是做其他 *****/Runtime.getRuntime().exec("C:/Windows/System32/cmd.exe /k start E:/酷狗/KGMusic/KuGou.exe"); // 通过cmd窗⼝执⾏命令Runtime.getRuntime().exec("C:/Windows/System32/cmd.exe /k start E:/php/Test/第⼀个html/界⾯.html"); // 通过cmd命令打开⼀个⽹页Runtime.getRuntime().exec("C:/Windows/System32/cmd.exe /k mkdir C:\\Users\\liqiang\\Desktop\\java键的1"); // 通过cmd创建⽬录⽤两个反斜杠Runtime.getRuntime().exec("C:/Windows/System32/cmd.exe /k mkdir C:\\Users\\liqiang\\Desktop\\java键的2"); // 通过cmd创建⽬录⽤两个反斜杠Runtime.getRuntime().exec("C:/Windows/System32/cmd.exe /c calc ");// 通过cmd打开计算器}@Testpublic void test2() throws IOException {/******** 可以通过cmd命令打开软件或者是做其他 *****/Runtime.getRuntime().exec("C:/Windows/System32/cmd.exe /c osk");// 通过屏幕软键盘}}另外也可以获取⼀些其他的JVM参数:long totalMemory = Runtime.getRuntime().totalMemory();//总内存long freeMemory = Runtime.getRuntime().freeMemory();//剩余内存long maxMemory = Runtime.getRuntime().maxMemory();//最⼤内存System.out.println(totalMemory/1024/1024+"MB");System.out.println(freeMemory/1024/1024+"MB");System.out.println(maxMemory/1024/1024+"MB");也可以直接执⾏⼀些命令:Runtime.getRuntime().exec("calc");//打开计算器补充:上⾯的⽅式都是异步运⾏的⽅式,也就是在执⾏命令之后会不等exec执⾏完就执⾏下⼀条语句,为了实现同步结果,或者为了获取返回的结果,参考:import java.io.IOException;import java.io.InputStream;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public final class Test {private static final Logger logger = LoggerFactory.getLogger(Test.class);public static void main(String[] args) throws NullPointerException {long start = System.currentTimeMillis();String srcPath = "C:/Users/liqiang/Desktop/ww/tt.docx", desPath = "C:/Users/liqiang/Desktop/ww";String command = "";String osName = System.getProperty("");if (osName.contains("Windows")) {command = "soffice --headless --convert-to pdf " + srcPath + " --outdir " + desPath;exec(command);}long end = System.currentTimeMillis();logger.debug("⽤时:{} ms", end - start);}public static boolean exec(String command) {Process process;// Process可以控制该⼦进程的执⾏或获取该⼦进程的信息try {logger.debug("exec cmd : {}", command);process = Runtime.getRuntime().exec(command);// exec()⽅法指⽰Java虚拟机创建⼀个⼦进程执⾏指定的可执⾏程序,并返回与该⼦进程对应的Process对象实例。

调用本地方法接口代码的方法

调用本地方法接口代码的方法

调用本地方法接口代码的方法全文共四篇示例,供读者参考第一篇示例:调用本地方法接口是在Java程序中调用本地方法的一种方法,通过本地方法接口,我们可以让Java程序调用已经编写好的本地函数,以实现一些特定的功能。

本地方法接口提供了一种将Java程序与操作系统原生功能结合的途径,使得Java程序在需要与底层系统进行交互时可以更加高效。

在Java中,本地方法接口是通过JNI(Java Native Interface)来实现的。

JNI允许Java程序通过本地方法调用底层C或C++编写的函数,以实现与底层系统的交互。

在使用本地方法接口时,需要编写对应的本地方法库,将需要调用的本地函数实现在本地方法库中,并在Java程序中声明本地方法接口,并在本地方法接口中引用对应的本地方法。

第二篇示例:为了提高软件系统的性能和灵活性,开发人员通常会将一些常用的功能封装成本地方法并通过接口供其他模块调用。

接下来我们将介绍如何调用本地方法接口代码的方法。

我们需要明确本地方法的概念。

本地方法即指在一个软件系统中直接调用操作系统或底层语言提供的接口函数。

这些接口函数通常包含在动态链接库(DLL)或共享库(SO)中,可以通过特定的语言来调用,比如C或C++。

在Java语言中,我们可以通过Java Native Interface(JNI)来调用本地方法。

JNI是一种Java调用C/C++本地方法的机制,通过JNI,我们可以将Java虚拟机(JVM)嵌入到本地代码中,进而实现Java与本地代码的无缝交互。

接下来,我们将介绍如何编写一个简单的本地方法接口代码,并通过JNI在Java中进行调用。

假设我们有一个C函数用于计算两个整数之和:```#include <jni.h>JNIEXPORT jint JNICALLJava_Sum_calculateSum(JNIEnv *env, jobject obj, jint a, jint b) {return a + b;}```该C函数用于计算两个整数的和,并定义为一个本地方法接口代码。

JNI编程实现(Windows)

JNI编程实现(Windows)

JNI编程实现(Windows)JNI(Java Native Interface)是一种用于在Java虚拟机(JVM)中调用本地代码的编程接口。

它允许Java程序与用其他编程语言编写的本地代码进行交互,如C,C++,甚至汇编语言。

通过JNI,Java程序可以调用本地代码中的函数,访问本地库中的变量,并且本地代码也可以通过回调函数调用Java程序中的方法。

在Windows平台下,实现JNI编程主要需要以下几个步骤:1. 编写Java程序:首先,我们需要编写一个Java程序作为JNI的客户端。

在Java程序中,我们需要声明native关键字,告诉编译器将这个方法实现委托给本地代码。

```javapublic class JNIDemopublic native void nativeMethod(; // 本地方法声明staticSystem.loadLibrary("nativeLib"); // 加载本地库}public static void main(String[] args)new JNIDemo(.nativeMethod(; // 调用本地方法}```2. 生成C/C++头文件:在命令行中,使用`javac`命令编译Java源文件,然后使用`javah`命令生成C/C++的头文件。

该头文件将包含Java类的方法签名,我们将在本地代码中使用这些方法签名来实现Java方法。

```shelljavac JNIDemo.javajavah -jni JNIDemo```生成的头文件`JNIDemo.h`内容如下:```c/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class JNIDemo */#ifndef _Included_JNIDemo#define _Included_JNIDemo#ifdef __cplusplusextern "C"#endif/** Class: JNIDemo* Method: nativeMethod* Signature: (V*/JNIEXPORT void JNICALL Java_JNIDemo_nativeMethod(JNIEnv *, jobject);#ifdef __cplusplus#endif#endif```3. 编写本地代码:编写C/C++源文件来实现Java中声明的本地方法。

java 中native的方法

java 中native的方法

java 中native的方法【原创版4篇】目录(篇1)1.Java 中的 native 方法概述2.native 方法的声明与调用3.native 方法的优点与局限性4.示例:使用 native 方法实现 Java 与 C 语言的交互正文(篇1)1.Java 中的 native 方法概述在 Java 语言中,native 方法是指那些不是由 Java 编译器编译而成的方法,而是由其他编程语言(如 C 或 C++)编写并编译成的本地代码。

这些本地代码可以直接在 Java 程序中调用,从而实现了 Java 与其他编程语言的交互。

native 方法主要用于实现 Java 与本地代码的交互,以完成一些 Java 语言本身无法实现或效率较低的任务。

2.native 方法的声明与调用在 Java 中,native 方法需要声明在 Java 类中,声明格式为:`native void methodName();`。

这里,methodName 为方法名,void 表示该方法不返回任何值。

需要注意的是,native 方法没有具体的实现,其实现部分需要用其他编程语言编写。

要调用 native 方法,只需在 Java 代码中像调用普通方法一样调用即可,例如:`System.loadLibrary("mylibrary");`。

这里,mylibrary 为动态链接库的名称。

3.native 方法的优点与局限性ative 方法的优点:a.可以直接调用其他编程语言编写的代码,实现 Java 与其他编程语言的交互。

b.可以使用其他编程语言提供的高效 API,提高程序的执行效率。

c.可以实现一些 Java 语言本身无法实现的功能。

ative 方法的局限性:a.不利于代码的跨平台性,因为不同平台的本地代码可能需要进行不同的修改。

b.可维护性较差,因为本地代码的修改可能导致 Java 代码的修改。

c.安全性较低,因为本地代码可以绕过 Java 的安全机制。

Java调用C++动态库具体实现

Java调用C++动态库具体实现

Java调⽤C++动态库具体实现在我们编写java程序中经常会⽤到native⽅法,这些native⽅法就是⽤C或者C++编写的动态库⽅法,如何实现java调⽤这些⽅法,以下是根据⾃⼰的学习经验总结如下:1.创建项⽬⾸先在Eclipse中创建⼀个项⽬,创建两个类第⼀个类是HelloWorld.java 第⼆个类是TestDll.java,HelloWorld.java 代码中是你要创建的本地库⽅法,要⽤关键字native申明。

例如:package com;public class HelloWorld {public native void sayHello();}TestDll.java实现对此⽅法的调⽤public class TestDLL {public static void main(String[] args){System.loadLibrary("HelloWorld"); //加载的HelloWorld为动态库dll的名字。

或者这⼀句放在HelloWorld.java中HelloWorld helloWorld = new HelloWorld();helloWorld.sayHello();}}2. ⽣成C/C++头⽂件在windows中打开⼀个命令窗⼝,进⼊jnitest⼯程所在⽬录下的bin⽬录如:D:\workspace\jnitest\bin。

键⼊javah -classpathD:\workspace\jnitest\bin HelloWorld命令⽣成头⽂件HelloWorld.h。

内容如下:/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_HelloWorld */#ifndef _Included_com_HelloWorld#define _Included_com_HelloWorld#ifdef __cplusplusextern"C" {#endif/** Class: com_HelloWorld* Method: sayHello* Signature: ()V*/JNIEXPORT void JNICALL Java_com_HelloWorld_sayHello(JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif注意不要修改此⽂件的代码3.编写本地⽅法实现⽤VC6创建HelloWorld Win32动态链接库⼯程。

实现jni方法

实现jni方法

实现JNI方法什么是JNI?JNI(Java Native Interface)是Java提供的一种机制,用于在Java程序中调用其他语言编写的本地代码(Native Code),比如C、C++等。

通过JNI,我们可以利用其他语言编写的高性能库或者使用底层系统功能。

为什么需要使用JNI?在某些情况下,使用Java编写的程序可能无法满足性能要求或者需要直接访问底层资源。

这时候,我们就可以使用JNI来调用本地代码,以获得更高的性能和更好的资源访问能力。

另外,有些库或者功能只有在特定平台上才可用,而这些平台可能没有提供对应的Java API。

这时候,我们也可以使用JNI来调用底层库。

JNI的工作原理JNI通过定义一组规范来实现Java与本地代码之间的交互。

主要包含以下几个方面:1.Java Native Method Interface:定义了Java方法与本地方法之间的映射关系。

2.Java数据类型映射:将Java数据类型映射到对应的本地数据类型。

3.调用约定和参数传递:定义了方法调用时参数传递和返回值处理等规则。

4.异常处理:定义了异常在Java和本地代码之间传递和处理的方式。

通过这些规范,我们可以在Java代码中声明本地方法,并在本地代码中实现这些方法。

然后通过JNI提供的接口,将Java方法与本地方法进行绑定。

如何实现JNI方法?要实现JNI方法,我们需要按照以下步骤进行:1.编写Java代码:首先,在Java代码中声明本地方法,并使用native关键字修饰。

例如:public class NativeExample {public native void nativeMethod();}2.生成JNI头文件:使用javac命令编译Java源文件,然后使用javah命令生成JNI头文件。

例如:javac NativeExample.javajavah -jni NativeExample这将生成一个名为NativeExample.h的头文件,其中包含了JNI方法的声明。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

在Windows 中实现Java 本地方法David WendtWebSphere DevelopmentResearch Triangle Park, NC1999 年5 月摘要本文为在 32 位 Windows 平台上实现 Java 本地方法提供了实用的示例步骤和准则这些示例包括传递和返回常用的数据类型本文中的示例使用 Sun Microsystems 公司创建的 Java Development Kit (JDK) 版本 1.1.6 和 Java 本地接口 (JNI) 规范用 C 语言编写的本地代码是用 Microsoft Visual C++ 编译器编译生成的简介本文提供调用本地 C 代码的 Java 代码示例包括传递和返回某些常用的数据类型本地方法包含在特定于平台的可执行文件中就本文中的示例而言本地方法包含在 Windows 32 位动态链接库 (DLL) 中不过我要提醒您对 Java 外部的调用通常不能移植到其他平台上在 applet 中还可能引发安全异常实现本地代码将使您的 Java 应用程序无法通过 100% 纯 Java 测试但是如果必须执行本地调用则要考虑几个准则1. 将您的所有本地方法都封装在单个类中这个类调用单个 DLL对于每种目标操作系统都可以用特定于适当平台的版本替换这个 DLL这样就可以将本地代码的影响减至最小并有助于将以后所需的移植问题包含在内2. 本地方法要简单尽量将您的 DLL 对任何第三方包括 Microsoft运行时 DLL 的依赖减到最小使您的本地方法尽量独立以将加载您的 DLL 和应用程序所需的开销减到最小如果需要运行时DLL必须随应用程序一起提供它们Java 调用 C对于调用 C 函数的 Java 方法必须在 Java 类中声明一个本地方法在本部分的所有示例中我们将创建一个名为 MyNative 的类并逐步在其中加入新的功能这强调了一种思想即将本地方法集中在单个类中以便将以后所需的移植工作减到最少示例 1 -- 传递参数在第一个示例中我们将三个常用参数类型传递给本地函数String int 和 boolean本例说明在本地 C 代码中如何引用这些参数public class MyNative{public void showParms( String s, int i, boolean b ){showParms0( s, i , b );}private native void showParms0( String s, int i, boolean b );static{System.loadLibrary( "MyNative" );}}请注意本地方法被声明为专用的并创建了一个包装方法用于公用目的这进一步将本地方法同代码的其余部分隔离开来从而允许针对所需的平台对它进行优化static 子句加载包含本地方法实现的 DLL下一步是生成 C 代码来实现 showParms0 方法此方法的 C 函数原型是通过对 .class 文件使用 javah 实用程序来创建的而 .class 文件是通过编译 MyNative.java 文件生成的这个实用程序可在 JDK 中找到下面是 javah 的用法javac MyNative.java将 .java 编译为 .classjavah -jniMyNative生成 .h 文件这将生成一个 MyNative.h 文件其中包含一个本地方法原型如下所示/** Class: MyNative* Method: showParms0* Signature: (Ljava/lang/String;IZ)V*/JNIEXPORT void JNICALL Java_MyNative_showParms0(JNIEnv *, jobject, jstring, jint, jboolean);第一个参数是调用 JNI 方法时使用的 JNI Environment 指针第二个参数是指向在此 Java 代码中实例化的 Java 对象 MyNative 的一个句柄其他参数是方法本身的参数请注意MyNative.h 包括头文件 jni.h jni.h 包含 JNI API 和变量类型包括jobject jstringjint jboolean等等的原型和其他声明本地方法是在文件 MyNative.c 中用 C 语言实现的#include <stdio.h>#include "MyNative.h"JNIEXPORT void JNICALL Java_MyNative_showParms0(JNIEnv *env, jobject obj, jstring s, jint i, jboolean b){const char* szStr = (*env)->GetStringUTFChars( env, s, 0 );printf( "String = [%s]\n", szStr );printf( "int = %d\n", i );printf( "boolean = %s\n", (b==JNI_TRUE ? "true" : "false") );(*env)->ReleaseStringUTFChars( env, s, szStr );}JNI API GetStringUTFChars用来根据 Java 字符串或 jstring 参数创建 C 字符串这是必需的因为在本地代码中不能直接读取 Java 字符串而必须将其转换为 C 字符串或 Unicode有关转换 Java 字符串的详细信息请参阅标题为 NLS Strings and JNI 的一篇论文但是jboolean 和 jint 值可以直接使用MyNative.dll 是通过编译 C 源文件创建的下面的编译语句使用 Microsoft Visual C++ 编译器cl -Ic:\jdk1.1.6\include -Ic:\jdk1.1.6\include\win32 -LD MyNative.c-FeMyNative.dll其中 c:\jdk1.1.6 是 JDK 的安装路径MyNative.dll 已创建好现在就可将其用于 MyNative 类了可以这样测试这个本地方法在 MyNative 类中创建一个 main 方法来调用 showParms 方法如下所示public static void main( String[] args ){MyNative obj =new MyNative();obj.showParms( "Hello", 23, true );obj.showParms( "World", 34, false );}当运行这个 Java 应用程序时请确保 MyNative.dll 位于 Windows 的 PATH 环境变量所指定的路径中或当前目录下当执行此 Java 程序时如果未找到这个 DLL您可能会看到以下的消息java MyNativeCan't find class MyNative这是因为 static 子句无法加载这个 DLL所以在初始化 MyNative 类时引发异常Java 解释器处理这个异常并报告一个一般错误指出找不到这个类如果用 -verbose 命令行选项运行解释器您将看到它因找不到这个 DLL 而加载 UnsatisfiedLinkError 异常如果此 Java 程序完成运行就会输出以下内容java MyNativeString = [Hello]int = 23boolean = trueString = [World]int= 34boolean = false示例 2 -- 返回一个值本例将说明如何在本地方法中实现返回代码将这个方法添加到 MyNative 类中这个类现在变为以下形式public class MyNative{public void showParms( String s, int i, boolean b ){showParms0( s, i , b );}public int hypotenuse( int a, int b ){return hyptenuse0( a, b );}private native void showParms0( String s, int i, boolean b );private native int hypotenuse0( int a, int b );static{System.loadLibrary( "MyNative" );}/* 测试本地方法 */public static void main( String[] args )MyNative obj =new MyNative();System.out.println( obj.hypotenuse(3,4) );System.out.println( obj.hypotenuse(9,12) );}}公用的 hypotenuse 方法调用本地方法 hypotenuse0 来根据传递的参数计算值并将结果作为一个整数返回这个新本地方法的原型是使用 javah 生成的请注意每次运行这个实用程序时它将自动覆盖当前目录中的 MyNative.h按以下方式执行 javahjavah -jni MyNative生成的 MyNative.h 现在包含 hypotenuse0 原型如下所示/** Class: MyNative* Method: hypotenuse0* Signature: (II)I*/JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0(JNIEnv *, jobject, jint, jint);该方法是在 MyNative.c 源文件中实现的如下所示#include <stdio.h>#include <math.h>#include "MyNative.h"JNIEXPORT void JNICALL Java_MyNative_showParms0(JNIEnv *env, jobject obj, jstring s, jint i, jboolean b){const char* szStr = (*env)->GetStringUTFChars( env, s, 0 );printf( "String = [%s]\n", szStr );printf( "int = %d\n", i );printf( "boolean = %s\n", (b==JNI_TRUE ? "true" : "false") );(*env)->ReleaseStringUTFChars( env, s, szStr );}JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0(JNIEnv *env, jobject obj, jint a, jint b)int rtn = (int)sqrt( (double)( (a*a) + (b*b) ) );return (jint)rtn;}再次请注意jint 和 int 值是可互换的使用相同的编译语句重新编译这个 DLLcl -Ic:\jdk1.1.6\include -Ic:\jdk1.1.6\include\win32 -LD MyNative.c-FeMyNative.dll现在执行 java MyNative 将输出 5 和 15 作为斜边的值示例 3 -- 静态方法您可能在上面的示例中已经注意到实例化的 MyNative 对象是没必要的实用方法通常不需要实际的对象通常都将它们创建为静态方法本例说明如何用一个静态方法实现上面的示例更改 MyNative.java 中的方法签名以使它们成为静态方法public static int hypotenuse( int a, int b ){return hypotenuse0(a,b);}...private static native int hypotenuse0( int a, int b );现在运行 javah 为 hypotenuse0 创建一个新原型生成的原型如下所示/** Class: MyNative* Method: hypotenuse0* Signature: (II)I*/JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0(JNIEnv *, jclass, jint, jint);C 源代码中的方法签名变了但代码还保持原样JNIEXPORT jint JNICALL Java_MyNative_hypotenuse0(JNIEnv *env, jclass cls, jint a, jint b){int rtn = (int)sqrt( (double)( (a*a) + (b*b) ) );return (jint)rtn;}本质上jobject 参数已变为 jclass 参数此参数是指向 MyNative.class 的一个句柄main 方法可更改为以下形式public static void main( String[] args ){System.out.println( MyNative.hypotenuse( 3, 4 ) );System.out.println( MyNative.hypotenuse( 9, 12 ) );}因为方法是静态的所以调用它不需要实例化 MyNative 对象本文后面的示例将使用静态方法示例 4 -- 传递数组本例说明如何传递数组型参数本例使用一个基本类型boolean并将更改数组元素下一个示例将访问 String非基本类型数组将下面的方法添加到 MyNative.java 源代码中public static void setArray( boolean[] ba ){for( int i=0; i < ba.length; i++ )ba[i] = true;setArray0( ba );}...private static native void setArray0( boolean[] ba );在本例中布尔型数组被初始化为 true本地方法将把特定的元素设置为 false同时在 Java 源代码中我们可以更改 main 以使其包含测试代码boolean[] ba = new boolean[5];MyNative.setArray( ba );for( int i=0; i < ba.length; i++ )System.out.println( ba[i] );在编译源代码并执行 javah 以后MyNative.h 头文件包含以下的原型/** Class: MyNative* Method: setArray0* Signature: ([Z)V*/JNIEXPORT void JNICALL Java_MyNative_setArray0(JNIEnv *, jclass, jbooleanArray);请注意布尔型数组是作为单个名为 jbooleanArray 的类型创建的基本类型有它们自已的数组类型如 jintArray 和 jcharArray非基本类型的数组使用 jobjectArray 类型下一个示例中包括一个 jobjectArray这个布尔数组的数组元素是通过 JNI 方法 GetBooleanArrayElements 来访问的针对每种基本类型都有等价的方法这个本地方法是如下实现的JNIEXPORT void JNICALL Java_MyNative_setArray0(JNIEnv *env, jclass cls, jbooleanArray ba){jboolean* pba = (*env)->GetBooleanArrayElements( env, ba, 0 );jsize len = (*env)->GetArrayLength(env, ba);int i=0;// 更改偶数数组元素for( i=0; i < len; i+=2 )pba[i] =JNI_FALSE;(*env)->ReleaseBooleanArrayElements( env, ba, pba, 0 );}指向布尔型数组的指针可以使用 GetBooleanArrayElements 获得数组大小可以用 GetArrayLength 方法获得使用 ReleaseBooleanArrayElements 方法释放数组现在就可以读取和修改数组元素的值了jsize 声明等价于 jint要查看它的定义请参阅 JDK 的 include 目录下的 jni.h 头文件示例 5 -- 传递 Java String 数组本例将通过最常用的非基本类型Java String说明如何访问非基本对象的数组字符串数组被传递给本地方法而本地方法只是将它们显示到控制台上 MyNative 类定义中添加了以下几个方法public static void showStrings( String[] sa ){showStrings0( sa );private static void showStrings0( String[] sa );并在 main 方法中添加了两行进行测试String[] sa = new String[] { "Hello,", "world!", "JNI", "is", "fun." };MyNative.showStrings( sa );本地方法分别访问每个元素其实现如下所示JNIEXPORT void JNICALL Java_MyNative_showStrings0(JNIEnv *env, jclass cls, jobjectArray sa){int len = (*env)->GetArrayLength( env, sa );int i=0;for( i=0; i < len; i++ ){jobject obj = (*env)->GetObjectArrayElement(env, sa, i);jstring str =(jstring)obj;const char* szStr = (*env)->GetStringUTFChars( env, str, 0 );printf( "%s ", szStr );(*env)->ReleaseStringUTFChars( env, str, szStr );}printf( "\n" );}数组元素可以通过 GetObjectArrayElement 访问在本例中我们知道返回值是 jstring 类型所以可以安全地将它从 jobject 类型转换为 jstring 类型字符串是通过前面讨论过的方法打印的有关在 Windows 中处理 Java 字符串的信息请参阅标题为 NLS Strings and JNI 的一篇论文示例 6 -- 返回 Java String 数组最后一个示例说明如何在本地代码中创建一个字符串数组并将它返回给 Java 调用者MyNative.java 中添加了以下几个方法public static String[] getStrings(){return getStrings0();}private static native String[] getStrings0();更改 main 以使 showStrings 将 getStrings 的输出显示出来MyNative.showStrings( MyNative.getStrings() );实现的本地方法返回五个字符串JNIEXPORT jobjectArray JNICALL Java_MyNative_getStrings0(JNIEnv *env, jclass cls){jstring str;jobjectArray args = 0;jsize len = 5;char* sa[] ={ "Hello,", "world!", "JNI", "is", "fun" };int i=0;args = (*env)->NewObjectArray(env, len, (*env)->FindClass(env, "java/lang/String"), 0);for( i=0; i < len; i++ ){str = (*env)->NewStringUTF( env, sa[i] );(*env)->SetObjectArrayElement(env, args, i, str);}return args;}字符串数组是通过调用 NewObjectArray 创建的同时传递了 String 类和数组长度两个参数Java String 是使用 NewStringUTF 创建的String 元素是使用 SetObjectArrayElement 存入数组中的调试现在您已经为您的应用程序创建了一个本地 DLL但在调试时还要牢记以下几点如果使用 Java 调试器 java_g.exe则还需要创建 DLL 的一个调试版本这只是表示必须创建同名但带有一个 _g 后缀的 DLL 版本就 MyNative.dll 而言使用 java_g.exe 要求在 Windows 的 PATH 环境指定的路径中有一个 MyNative_g.dll 文件在大多数情况下这个 DLL 可以通过将原文件重命名或复制为其名称带缀 _g 的文件现在Java 调试器不允许您进入本地代码但您可以在 Java 环境外使用 C 调试器如 Microsoft Visual C++调试本地方法首先将源文件导入一个项目中将编译设置调整为在编译时将 include 目录包括在内c:\jdk1.1.6\include;c:\jdk1.1.6\include\win32将配置设置为以调试模式编译 DLL在 Project Settings 中的 Debug 下将可执行文件设置为 java.exe或者 java_g.exe但要确保您生成了一个 _g.dll 文件程序参数包括包含 main 的类名如果在 DLL 中设置了断点则当调用本地方法时执行将在适当的地方停止下面是设置一个 Visual C++ 6.0 项目来调试本地方法的步骤1. 在 Visual C++ 中创建一个 Win32 DLL 项目并将 .c 和 .h 文件添加到这个项目中2. 在 Tools 下拉式菜单的 Options 设置下设置 JDK 的 include 目录下面的对话框显示了这些目录3. 选择 Build 下拉式菜单下的 Build MyNative.dll 来建立这个项目确保将项目的活动配置设置为调试这通常是缺省值4. 在 Project Settings 下设置 Debug 选项卡来调用适当的 Java 解释器如下所示当执行这个程序时忽略在 java.exe 中找不到任何调试信息的消息当调用本地方法时在 C 代码中设置的任何断点将在适当的地方停止 Java 程序的执行其他信息JNI 方法和 C++上面这些示例说明了如何在 C 源文件中使用 JNI 方法如果使用 C++则请将相应方法的格式从(*env)->JNIMethod( env, .... );更改为env->JNIMethod( ... );在 C++ 中JNI 函数被看作是 JNIEnv 类的成员方法字符串和国家语言支持本文中使用的技术用 UTF 方法来转换字符串使用这些方法只是为了方便起见如果应用程序需要国家语言支持 (NLS)则不能使用这些方法有关在 Windows 和 NLS 环境中处理 Java 字符串正确方法请参标题为 NLS Strings and JNI 的一篇论文小结本文提供的示例用最常用的数据类据如 jint 和 jstring说明了如何实现本地方法并讨论了 Windows 特定的几个问题如显示字符串本文提供的示例并未包括全部 JNI JNI 还包括其他参数类型如 jfloat jdouble jshort jbyte 和 jfieldID以及用来处理这些类型的方法有关这个主题的详细信息请参阅 Sun Microsystems 提供的 Java 本地接口规范作者简介David Wendt 是 IBM WebSphere Studio 的一名程序员该工作室位于北卡罗莱纳州的 Research Triangle Park可以通过 wendt@ 与他联系。

相关文档
最新文档