JNI 实例调用

java c/cpp互相调用实例(姊妹篇之一)
----------java调用c/cpp
[url=http://www.iteye.com/topic/460152](之二c/cpp调用java)[/url]

此文章纯粹实例操作,关于jni已经有不少人不少文章讲的很清楚了,所以就不罗列理论了。

看了kimmking的[color=blue]JNI技术实践小结[/color],又读了danlley的[color=blue]Java JNI 编程进阶[/color],这些文章中都是自己调用自己,方法很java化,而对于真正的调用dll还是不理解,心中一直存在问题:现在系统中已经有的dll我该如何去调用?如果一个大工程里需要cpp和java一起开发,cpp给出接口、SDK,我该如何处理?
带着这些疑问我决定从cpp到java的jni调用这个全过程亲自动手操作一下。

完成此示例需要下列工具/环境:
1、java环境(废话谁都知道)
2、编译c/cpp的工具。推荐用vs/vc++,我用的是vs2008


一 先制作一个系统中有的DLL文件(cpp给出的sdk接口)

既然是测试我们就把我们这个dll叫做testDll吧,为了简单其间,我只写一个add方法,就是简单的2个数字相加,对于真正的开发中我们肯定会遇到其他类型,java到c/cpp中类型需要转换,具体类型转换对应关系g一下就能得到,我也不在列举。c/cpp中一个class一般包含2个文件,一个头文件定义(*.h),一个文件主体(*.c/*.cpp)。啰嗦了这么多还是直接动手吧,先在vs2008中建立一个工程(当然你也可以直接编写不用这些IDE工具,gcc g++的命令自己g。下同,不在注释不在废话),选取win32工程
[img]/upload/attachment/141051/b6db63fc-df70-37cd-bfe1-49d615c0d1e7.jpg[/img]
键入工程名字testDll,点击next选取DLL,然后点击完成
[img]/upload/attachment/141056/51aad895-1607-3cb8-b659-d7d6cad19580.jpg[/img]
打开我们的testdll.cpp,添加进我们的add方法

int add(int a,int b){
return a+b;
}

注意到文件列表里并没有testDll.h,因为我们要给出调用者一个接口,如果不给头文件,人家就没办法调用,所以我们就必须添加一个头文件testDll.h。

#ifdef TEST_DLL
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif

TEST_API int add(int,int);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
在这个头文件中我们把我们的add方法给定义了进去。注意到testdll.cpp中#include "stdafx.h",所以我们就把这个testDll.h include进stdafx.h里面。

按道理说我们的这个dll已经完成了,但是一般c/cpp给接口SDK的时候大都给.h和.lib,为了一步生成dll和lib,我们添加进一个testDll.def,有了这个文件就可以一步生成dll和lib。在source file里右键add new item ,选择Module-Definition File
[img]/upload/attachment/141066/2e61f5a5-a521-3bdb-9d69-98e7abbf1420.jpg[/img]
键入testDll,OK了,我们可以直接build了。生成testDll.dll和testDll.lib。

把testDll.dll扔到system32目录里等待我们高大威猛的java jni调用。

二 JNI

2.1 编写java文件

为了显示我们的与众相同,我们就把我们的这个java文件命名为Demo.java顺便直接带上包名
,因为我们知道人家给我们的接口里有个add方法,所以我们就直接来个调用吧。

package com.testJni.testDemo;

public class Demo {
static
{
//System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("testDll");
System.loadLibrary("jniDll");
}
public native static int add(int a,int b);

}
demo.java代码暂时如此,我们把将要生成的jni的dll叫做jniDll,有童鞋讲,我不想用你这个烂名字jniDll多俗啊,没关系,你可以换,随你换,生成文件后你再换也可以,现在换也可以。

2.2 生成.h头文件

javah命令,不多讲。生成的文件com_testJni_testDemo_Demo.h这个文件的命名规则我就不多讲了,一目了然。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_testJni_testDemo_Demo */

#ifndef _Included_com_testJni_testDemo_Demo
#define _Included_com_testJni_testDemo_Demo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_testJni_testDemo_Demo
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add
(JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif


2.3 用c/cpp实现这个头文件

c/cpp中已经实现了这个add方法,我们只需要调用就可以啦。所以直接vs2008中建立一个dll工程,工程名我们就叫jniDll,具体过程不再多讲,方法同上面testDll的建立一样。在这个工程里kimmking把需要引用的包、文件等已经讲的很清楚了。打开jniDll.cpp,添加下面代码
JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add
(JNIEnv *env,jclass jobject,jint a,jint b){

return add(a,b);
}
因为int对应的类型就刚好是jint,所以就不需要转换,其他需要转换的类型自己g对应关系转换,注意释放。

这个工程里我们还需要打开 stdafx.h添加
#include <jni.h>

#include "testDll.h"
#include "com_testJni_testDemo_Demo.h"


在编译这个jniDll工程的时候需要引入testDll.h,com_testJni_testDemo_Demo.h,另外添加testDll.lib这个依赖。
[img]/upload/attachment/141078/b70fe387-8291-30de-80ba-8e811f1079af.jpg[/img]

好了做好这些后,build下,生成了我们期待已久的jniDll.dll,把这个dll同样扔到system32下。

三 测试


本人特懒,不想写多余的class,所以直接修改Demo.java 这也是刚才为什么讲暂时如此的原因
package com.testJni.testDemo;

public class Demo {
static
{
//System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("testDll");
System.loadLibrary("jniDll");
}
public native static int add(int a,int b);
public static void main(String[] args) {
System.out.println(add(7,2));
}
}


四 最后补充

如果系统已经加载过c/cpp的dll,我们就不用再System.loadLibrary("testDll")了,加载一遍就可以了,因为我们刚才写的testDll系统没有加载,所以我就加载了一下。对于多个dll可以写多个System.loadLibrary去加载,修改static{}里面的内容不需要重新生成dll,除非你多加了一个调用方法,如果你看清楚规则,就不用javah命令就可以直接编写头文件,用javah太麻烦了。

【参考文章】
[url=http://www.iteye.com/topic/304594]http://www.iteye.com/topic/304594[/url] JNI技术实践小结--原理分析和详细步骤截图说明
[url=http://www.iteye.com/topic/295776?page=1]http://www.iteye.com/topic/295776?page=1[/url] Java JNI 编程进阶
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java调用JNI实例的过程如下: 在Java调用JNI实例的第一步是通过System.loadLibrary()方法加载包含本地函数实现的动态链接库。这将使得Java程序能够找到并访问JNI实例中的方法。 接下来,在Java代码中声明一个native方法,这个方法将由JNI实例来实现。native关键字告诉编译器该方法是一个JNI方法。 然后,使用javah命令自动生成一个C/C++头文件,该头文件中包含了Java声明的native方法的函数原型。头文件的生成步骤是在命令行中进入Java源代码目录,并执行javah命令。 接下来,打开生成的头文件,将native方法的函数原型拷贝到一个C/C++源文件中,并实现该方法。 在C/C++源文件中,需要包含jni.h头文件,并实现native方法的功能。在实现JNI方法时,可以使用JNIEnv接口调用Java方法,通过JNI实例Java对象进行交互。 最后,使用C/C++的编译器将源文件编译成动态链接库。 在Java代码中,可以通过调用声明的native方法来使用JNI实例,这样就可以调用C/C++中实现的功能了。 需要注意的是,Java和C/C++之间的数据类型转换可能需要注意,因为Java和C/C++使用不同的数据类型系统。为了正确传递和处理参数,可能需要使用JNIEnv接口的一些方法来处理数据类型的转换。 总结来说,Java调用JNI实例的过程包括加载JNI实例的动态链接库、声明native方法、使用javah命令自动生成头文件、实现native方法的功能、编译源文件成动态链接库、通过调用native方法来使用JNI实例。 ### 回答2: Java调用JNI实例是指在Java程序中使用JNI技术(Java Native Interface)来调用本地方法。 JNIJava与本地代码之间的桥梁,它允许Java程序在运行时调用本地编程语言(如C、C++)编写的代码。这样做的好处是可以结合Java的跨平台特性和本地编程语言的高效性能。 要在Java程序中调用JNI实例,首先需要编写本地代码。以C语言为例,我们需要编写一个与Java类对应的本地方法。 编写本地方法时,需要使用特定的修饰符来表明这是一个本地方法,并且使用JNI提供的函数来与Java交互。然后将本地代码编译成动态链接库(如.so文件)。 然后,在Java程序中通过System.loadLibrary方法加载动态链接库。加载成功后,就可以通过Java调用本地方法了。 在调用本地方法时,需要使用native关键字来声明这是一个本地方法,并且使用JNI提供的接口来调用本地方法。 在调用JNI实例时,需要注意以下几点: 1. 确保本地代码与Java代码的数据类型匹配,可以使用JNI提供的函数转换数据类型。 2. 传递参数时,可以将Java的对象、基本数据类型或数组作为参数传递给本地方法。 3. 在本地方法中修改Java的对象时,需要使用JNI提供的函数来获取并修改Java对象的属性或调用Java对象的方法。 总结: Java调用JNI实例是一种充分利用Java跨平台特性和本地编程语言高性能的方式。通过编写本地代码并加载动态链接库,可以在Java程序中调用本地方法。在调用JNI实例时,需要注意数据类型匹配和参数传递等问题。 ### 回答3: Java调用JNIJava Native Interface)是一种机制,用于在Java程序中调用本机(Native)方法。Java开发者可以使用JNI将具有特定目标平台相关的操作或功能集成到Java应用程序中。 为了实现Java调用JNI,开发者首先需要编写一个Java类,其中包含用于调用本机方法的声明。然后,在本机方法中编写原生代码,以实现需要的功能。在编写完本机代码后,需要将其编译为动态连接库(.dll,.so等),以供Java程序调用。 在Java类中,使用`native`关键字声明本机方法。然后,通过JavaJNI库提供的函数,将本机方法与本机库中对应的函数进行关联。具体步骤如下: 1. 编写Java类,并在其中声明本机方法的原型,使用`native`关键字标记这些方法。 2. 使用Java的`javac`命令编译Java类,生成字节码文件。 3. 使用Java的`javah`命令生成头文件,该头文件包含了本机方法的声明。 4. 在C/C++中编写实现本机方法的代码,并将其编译为动态连接库。可以根据平台的不同,使用不同的编译选项和工具链进行编译。 5. 将生成的动态连接库与Java程序绑定。这可以通过在Java程序中使用`System.loadLibrary("library_name")`的方式来实现,其中`library_name`为动态连接库的名称。 6. 在Java程序中调用本机方法,通过JNI库提供的函数进行连接。 需要注意的是,Java调用JNI的过程需要遵循特定的规范和约定,以确保本机方法与Java代码之间的正确交互。此外,使用JNI可能会涉及到与本机平台相关的问题,比如内存管理和线程安全等。因此,在使用JNI时,开发者需要仔细考虑潜在的问题,并进行适当的测试和调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值