java c/cpp互相调用实例

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

看了kimmking的 JNI技术实践小结,又读了danlley的 Java JNI 编程进阶,这些文章中都是自己调用自己,方法很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工程

键入工程名字testDll,点击next选取DLL,然后点击完成

打开我们的testdll.cpp,添加进我们的add方法
C++代码 复制代码  收藏代码
  1. int add(int a,int b){    
  2.     return a+b;    
  3. }  

注意到文件列表里并没有testDll.h,因为我们要给出调用者一个接口,如果不给头文件,人家就没办法调用,所以我们就必须添加一个头文件testDll.h。
C++代码 复制代码  收藏代码
  1. #ifdef TEST_DLL   
  2. #define TEST_API __declspec(dllexport)   
  3. #else   
  4. #define TEST_API __declspec(dllimport)   
  5. #endif   
  6.   
  7. /* Set up for C function definitions, even when using C++ */  
  8. #ifdef __cplusplus   
  9. extern "C" {   
  10. #endif   
  11.   
  12. TEST_API int add(int,int);   
  13.   
  14. /* Ends C function definitions when using C++ */  
  15. #ifdef __cplusplus   
  16. }   
  17. #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

键入testDll,OK了,我们可以直接build了。生成testDll.dll和testDll.lib。

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

二 JNI

2.1 编写java文件

为了显示我们的与众相同,我们就把我们的这个java文件命名为Demo.java顺便直接带上包名
,因为我们知道人家给我们的接口里有个add方法,所以我们就直接来个调用吧。
Java代码 复制代码  收藏代码
  1. package com.testJni.testDemo;   
  2.   
  3. public class Demo {   
  4.     static  
  5.     {   
  6.         //System.out.println(System.getProperty("java.library.path"));   
  7.         System.loadLibrary("testDll");   
  8.         System.loadLibrary("jniDll");   
  9.     }   
  10.     public native static int add(int a,int b);    
  11.        
  12. }  
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这个文件的命名规则我就不多讲了,一目了然。
C++代码 复制代码  收藏代码
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>   
  3. /* Header for class com_testJni_testDemo_Demo */  
  4.   
  5. #ifndef _Included_com_testJni_testDemo_Demo   
  6. #define _Included_com_testJni_testDemo_Demo   
  7. #ifdef __cplusplus   
  8. extern "C" {   
  9. #endif   
  10. /*  
  11.  * Class:     com_testJni_testDemo_Demo  
  12.  * Method:    add  
  13.  * Signature: (II)I  
  14.  */  
  15. JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add   
  16.   (JNIEnv *, jclass, jint, jint);   
  17.   
  18. #ifdef __cplusplus   
  19. }   
  20. #endif   
  21. #endif  


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

c/cpp中已经实现了这个add方法,我们只需要调用就可以啦。所以直接vs2008中建立一个dll工程,工程名我们就叫jniDll,具体过程不再多讲,方法同上面testDll的建立一样。在这个工程里kimmking把需要引用的包、文件等已经讲的很清楚了。打开jniDll.cpp,添加下面代码
C++代码 复制代码  收藏代码
  1. JNIEXPORT jint JNICALL Java_com_testJni_testDemo_Demo_add   
  2. (JNIEnv *env,jclass jobject,jint a,jint b){   
  3.   
  4.     return add(a,b);   
  5. }  
因为int对应的类型就刚好是jint,所以就不需要转换,其他需要转换的类型自己g对应关系转换,注意释放。

这个工程里我们还需要打开 stdafx.h添加
C++代码 复制代码  收藏代码
  1. #include <jni.h>   
  2.   
  3. #include "testDll.h"   
  4. #include "com_testJni_testDemo_Demo.h"  


在编译这个jniDll工程的时候需要引入testDll.h,com_testJni_testDemo_Demo.h,另外添加testDll.lib这个依赖。


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

三 测试


本人特懒,不想写多余的class,所以直接修改Demo.java 这也是刚才为什么讲暂时如此的原因
Java代码 复制代码  收藏代码
  1. package com.testJni.testDemo;   
  2.   
  3. public class Demo {   
  4.     static  
  5.     {   
  6.         //System.out.println(System.getProperty("java.library.path"));   
  7.         System.loadLibrary("testDll");   
  8.         System.loadLibrary("jniDll");   
  9.     }   
  10.     public native static int add(int a,int b);    
  11.     public static void main(String[] args) {   
  12.         System.out.println(add(7,2));   
  13.     }   
  14. }  
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太麻烦了。

【参考文章】
http://www.iteye.com/topic/304594 JNI技术实践小结--原理分析和详细步骤截图说明
http://www.iteye.com/topic/295776?page=1 Java JNI 编程进阶
  • 大小: 46.6 KB
  • 大小: 25.8 KB
  • 大小: 57.9 KB
  • 大小: 55.8 KB
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android Studio中调用已有的C++实例,可以使用JNI(Java Native Interface)来实现。JNI是Java平台上的一种机制,它允许Java应用程序通过本地方法调用来访问本地代码(如C/C++代码)。 以下是实现步骤: 1. 创建Java类和C++类 首先,创建一个Java类来调用C++代码。然后,创建一个C++类,它将包含你希望从Java代码中调用的方法。 例如,我们将创建一个名为"NativeClass"的Java类,其中包含一个名为"nativeMethod"的本地方法。然后,我们将创建一个名为"NativeClassImpl"的C++类,其中包含一个名为"nativeMethodImpl"的方法。 2. 生成C++头文件 为了让Java代码知道如何调用C++代码,需要生成一个C++头文件。你可以使用Java Native Interface工具(javah)来生成。 在Android Studio中,可以在终端中使用以下命令生成头文件: ``` javah -jni com.example.NativeClass ``` 这将生成一个名为"com_example_NativeClass.h"的头文件,其中包含了你的Java类的本地方法的声明。 3. 实现本地方法 接下来,需要在C++类中实现本地方法。在我们的示例中,我们将实现"nativeMethodImpl"方法。 ``` #include <jni.h> extern "C" { JNIEXPORT void JNICALL Java_com_example_NativeClass_nativeMethod(JNIEnv *env, jobject thiz) { // 实现本地方法 } } ``` 注意,我们使用了extern "C"来确保函数名遵循C语言的命名规则,以便Java代码可以正确地调用它。 4. 将C++代码添加到项目中 将C++代码添加到Android Studio项目中。你可以将C++代码放在一个单独的.cpp文件中,或者将其添加到现有的C++文件中。 5. 将C++代码编译为共享库 要在Android应用程序中使用C++代码,需要将其编译为共享库。你可以使用Android NDK工具链来编译C++代码并生成共享库。 在Android Studio中,可以使用以下步骤将C++代码编译为共享库: - 在项目根目录下创建一个名为"jni"的文件夹。 - 将C++源代码文件添加到"jni"文件夹中。 - 创建一个名为"Android.mk"的文件,其中包含有关如何编译和链接C++代码的信息。 - 创建一个名为"Application.mk"的文件,其中包含有关编译选项的信息。 6. 在Java代码中加载共享库 最后,在Java代码中加载C++共享库,并使用System.loadLibrary()方法加载它。 例如,在我们的示例中,我们将在NativeClass类的静态初始化块中加载共享库: ``` static { System.loadLibrary("native_lib"); } ``` 这将加载名为"libnative_lib.so"的共享库。 7. 调用本地方法 现在,你可以在Java代码中调用本地方法。在我们的示例中,我们将在NativeClass类中调用nativeMethod()方法。 ``` public class NativeClass { static { System.loadLibrary("native_lib"); } public native void nativeMethod(); } ``` 这将调用名为"nativeMethodImpl"的C++方法。 希望这些步骤可以帮助你在Android Studio中调用已有的C++实例

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值