JNI教程
一、什么是JNI
JNI(Java Native Interface ),它是Java SDK的一部分,主要用于实现Java对其他语言编写的代码和库的调用,比如C和C++。JNI提供的API也能让JVM嵌入其他的本地代码,实现本地代码对Java代码的调用。本教程主要讲解的就是Java和本地代码的互调,以及C/C++中的数据类型与Java中的数据类型的关系。
二、需要的工具和库
- Java编译器:javac.exe
- Java虚拟机:java.exe
- C头文件产生器:javah.exe
- JNI的库文件(jvm.lib 或jvm.dll(.so))和头文件 (jni.h)
- 一个C和C++编译器
前面四个是JDK自带的放在%JAVA_HOME%\bin目录下面,最后一个工具根据你的平台不同有不同的选择。比如在Windows平台我们可以使用Mircosoft的编译器,在基于UNIX的系统下则可以使用GCC
三、Java调用C++
- 使用场景
- 对代码运行效率要求比较的,你可以采用稍底层更快的语言来编写,比如C/C++这样的本地代码(native code)。
- 你想要复用以前C/C++写的代码库
- 你需要一个平台相关的但是Java标准库又不支持的
- 使用步骤
通常我们完成Java调用C++需要以下6步
- 编写Java代码。这Java代码需要做3件事情:声明要调用的本地方法;加载包含了本地代码的共享库;调用本地方法。
- 编译Java代码。
- 创建C/C++头文件。这个C/C++头文件用于去声明将要调用的本地方法的签名,这个头文件使用C/C++去实现,并生产动态库。
- 编写C/C++的实现。实现第三步生成的头文件。
- 创建一个共享库。
- 运行Java代码。检测它是否正确工作。
- 示例代码
由于本示例只是测试Jni的调用,所以只写几个简单的方法。
1. 编写Java代码
1: public class Sample12: {3: public native int intMethod(int n);4: public native boolean booleanMethod(boolean bool);5: public native String stringMethod(String text);6: public native int intArrayMethod(int[] intArray);7: public static void main(String[] args)8: {9: System.loadLibrary("Sample1");10: Sample1 sample = new Sample1();11: int square = sample.intMethod(5);12: boolean bool = sample.booleanMethod(true);13: String text = sample.stringMethod("JAVA");14: int sum = sample.intArrayMethod(15: new int[]{1,1,2,3,5,8,13} );16: System.out.println("intMethod: " + square);17: System.out.println("booleanMethod: " + bool);18: System.out.println("stringMethod: " + text);19: System.out.println("intArrayMethod: " + sum);20: }21: }PS:native关键字表示此方法由外部实现。
2.编译Java代码
3.创建C/C++头文件
头文件分析:
JNIEXPORT:导出函数表示符号,JNICALL是调用约定(默认是stdcall),函数名是由Java前缀加类名在加方法名。jint,jboolean, jstring, jintarray和jobect是Java映射到C/C++中的类型,所有对应数据类型列表参加附录。JNIEnv:是Java虚拟机给我们提供的可调用的API。如下图
更多的常见jni.h
PS:参数中的jobject形参传递的是一个当前类对象的引用
4.编写C/C++的实现
1: #include "Sample1.h"
2: #include <string.h>
3:
4: /*
5: * Class: Sample1
6: * Method: intMethod
7: * Signature: (I)I
8: */
9: JNIEXPORT jint JNICALL Java_Sample1_intMethod
10: (JNIEnv * env, jobject obj, jint num)
11: {
12: return num * num;
13: }
14:
15: /*
16: * Class: Sample1
17: * Method: booleanMethod
18: * Signature: (Z)Z
19: */
20: JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod
21: (JNIEnv * env, jobject obj, jboolean boolValue)
22: {
23: return !boolValue;
24: }
25:
26: /*
27: * Class: Sample1
28: * Method: stringMethod
29: * Signature: (Ljava/lang/String;)Ljava/lang/String;
30: */
31: JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
32: (JNIEnv * env, jobject obj, jstring strValue)
33: {
34: const char* str = (*env)->GetStringUTFChars(env, strValue, 0);
35: char cap[128];
36: strcpy(cap, str);
37: (*env)->ReleaseStringUTFChars(env, strValue, str);
38: return (*env)->NewStringUTF(env, strupr(cap));
39: }
40:
41: /*
42: * Class: Sample1
43: * Method: intArrayMethod
44: * Signature: ([I)I
45: */
46: JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod
47: (JNIEnv * env, jobject obj, jintArray arrayValue )
48: {
49: int i, sum = 0;
50: jsize len = (*env)->GetArrayLength(env, arrayValue);
51: jint* data = (*env)->GetIntArrayElements(env, arrayValue, 0);
52: for (i = 0; i < len; ++i)
53: {
54: sum += data[i];
55: }
56: (*env)->ReleaseIntArrayElements(env, arrayValue, data, 0);
57: return sum;
58: }
5.创建一个共享库
如果对使用cl命令生产动态库不熟悉,可以使用VS生成动态库。
6.运行Java代码
四、C/C++调用Java
- 使用场景
- 在开发Android平台的游戏时,也需要通过Jni来调用第三方平台SDK。
- 你想要去实现一个平台无关的代码。
- 你想在本地代码中使用Java编写的代码。
- 你想使用Java标准库带来的好处。
- 使用步骤
通常我们完成C/C++调用Java需要以下4步
- 编写Java代码。使用Java代码去完成我们需要完成的功能 。
- 编译Java代码。 将编写好的Java代码生成字节码。
- 编写C/C++代码。用于去调用我们Java编写的代码
- 运行本地代码。
- 示例代码
1. 编写Java代码,如下:
1: import java.lang.String;2:3: public class Sample24: {5: public Sample2(String strValue)6: {7: _strValue = strValue;8: }9: public static int intMethod(int n)10: {11: return n*n;12: }13:14: public static boolean booleanMethod(boolean bool)15: {16: return !bool;17: }18:19: public void SetString(String str)20: {21: _strValue = str;22: }23:24: public String GetString()25: {26: return _strValue;27: }28:29: private String _strValue ;30: }
2. 编译Java代码
3. 编写C/C++代码
这一步也是最关键的一步,因为这里牵涉到Jni API的调用,比如创建JVM,在JVM中查找类,查找方法和调用方法。更多的API可以参见jni.h头文件。
所有Java的字节码都必须在JVM中执行,所有我们的第一件事情就是要创建JVM。如何创建呢?调用JDK提供的库文件(jvm.dll或jvm.so)中的函数。
1: // CCallJava.cpp : Defines the entry point for the console application.2: //3:4: #include "stdafx.h"5:6: #include <jni.h>7: #include <string.h>8: #include <exception>9:10: int _tmain(int argc, _TCHAR* argv[])11: {12: //构造初始化参数13: JavaVMOption options;14: JavaVMInitArgs vm_args;15: JNIEnv* env;16: JavaVM* jvm;17: long status;18: jclass cls;19: jmethodID mid;20: jint square;21: jboolean not;22:23: options.optionString = "-Djava.class.path=./../../";24: memset(&vm_args, 0, sizeof(vm_args));25: vm_args.version = JNI_VERSION_1_2;26: vm_args.nOptions = 1;27: vm_args.options = &options;28:29: //创建JVM30: status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);31: if (status != JNI_ERR)32: {33: cls = env->FindClass("Sample2");34: if (cls != 0 )35: {36: //获取构造函数37: jmethodID cstrctMid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");38: jobject obj = 0;39: if (cstrctMid != 0)40: {41: jstring strValue = env->NewStringUTF("This is testing string.");42: obj = env->NewObject(cls, cstrctMid, strValue);43: }44:45: mid = env->GetStaticMethodID( cls, "intMethod", "(I)I");46: if (mid != 0 )47: {48: square = env->CallStaticIntMethod(cls, mid, 5);49: printf("Result of intMethod: %d\n", square);50: }51:52: mid = env->GetStaticMethodID(cls, "booleanMethod", "(Z)Z");53: if (mid != 0 )54: {55: not = env->CallStaticBooleanMethod(cls, mid, 1);56: printf("Result of booleanMethod: %d\n", not);57: }58:59: mid = env->GetMethodID(cls, "SetString", "(I)V");60: if (mid != 0)61: {62: env->CallVoidMethod(obj, mid, 100);63: }64:65: mid = env->GetMethodID(cls, "GetString", "()Ljava/lang/String;");66: if (mid != 0)67: {68: jstring str = (jstring)(env->CallObjectMethod(obj, mid));69: const char* strResult = env->GetStringUTFChars(str, false);70: printf("Result of GetString: %s\n", strResult);71: }72: }73: jvm->DestroyJavaVM();74: }75: getchar();76: }77:
Ps:
(1)如果你的是64的JDK在变编译C++的时候务必选择x64位的程序。
(2)在使用C++中使用java的非基础数据类型时,请注意在后面加上分号。例如:
一个public String GetString()Java函数,对应的C++的签名则是这样的:"()Ljava/lang/String;"
五、高级
六、附录
附录A:JNI的类型
附录B:JNI方法的签名的组成规则
注意:
(1)class类型的最后一个分号不是分割符号,而是这个类型的结束标志。
(2)必须使用(/)代替(.)来作为包之间的分割。
JNI教程的更多相关文章
- JNI教程与技术手册
转载请标明出处:http://blog.csdn.net/shensky711/article/details/52806794 本文出自: [HansChen的博客] 概述 对于JNI,有些童鞋在没 ...
- Android JNI 学习(二):JNI 设计机制
本章我们重点说明以下JNI设计的问题,本章中提到的大多数设计问题都与native方法有关.至于调用相关的API的设计,我们会在后面进行介绍. 一.JNI接口函数和指针 native 代码通过调用JNI ...
- Android JNI 学习(一):JNI 简介
JNI 即 Java Native Interface 是 native 编程接口,它允许在Java虚拟机(VM)内运行Java代码与其他编程语言(主要是C和C++)编写的应用程序和库进行交互操作. ...
- JNI详解---从不懂到理解
转载:https://blog.csdn.net/hui12581/article/details/44832651 Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 C ...
- Android Jni 调用
Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 Chap 3:javah命令帮助信息... 16 Chap 4:用javah产生一个.h文件... 17 Chap5:j ...
- GitHub 优秀的 Android 开源项目(转)
今天查找资源时看到的一篇文章,总结了很多实用资源,十分感谢原作者分享. 转自:http://blog.csdn.net/shulianghan/article/details/18046021 主要介 ...
- GitHub 优秀的 Android 开源项目
转自:http://blog.csdn.net/shulianghan/article/details/18046021 主要介绍那些不错个性化的View,包括ListView.ActionBar.M ...
- android的快速开发框架集合
出自:http://blog.csdn.net/shulianghan/article/details/18046021 1.Afinal (快速开发框架) 简介:http://www.oschin ...
- GitHub 优秀Android 开源项目
阅读目录 1.Xabber客户端 2.oschina客户端 3.手机安全管家 4.星座连萌 5.玲闹铃 6.魔乐盒 7.PWP日历 8.Apollo音乐播放器 9.夏普名片识别 10.高仿人人网 11 ...
随机推荐
- 5.6 安装Virtual box
本以为安装虚拟机很复杂的样子,经过kevin一指点,发现soeasy.废话少说,直接上图片: 将安装包放到自己的目录下: 安装完后,可以在搜索框中搜索:virtual 会出现安装好的虚拟机盒子.
- 20169201 2016-2017-2 实验二《Java面向对象程序设计》
实验一:程序设计中临时变量的使用 代码托管 1.删除数组中的元素5 for(int i = 4; i < arr.length - 1; i ++){ arr[i] = arr[i + 1]; ...
- asp.net core 邮件发送
由于core不带smpt 所以借助MimeKit 以163邮箱为例 var message = new MimeMessage ();message.From.Add (new MailboxAddr ...
- 关于PHP在企业级开发领域的访谈——企业级开发,PHP准备好了吗?
关于PHP在企业级开发领域的访谈 ——企业级开发,PHP准备好了吗? 转自:http://www.nowamagic.net/librarys/veda/detail/256 虽然PHP是Web应用开 ...
- 第一个Python工程
创建你的第一个Python程序 如果你曾经很熟悉visual studio的工作方式.可能对python不习惯. 工程通常只与你使用的IDLE有关系.这些工具习惯将文档,编译,测试集成一体.所以就存在 ...
- webpack -- 多页面简单小例
有时单页面并不能满足我们的业务需求,就需要去构建多页面应用,以下为简单小例: entry:{ index:'./src/module/index/index.js', student:'./src/m ...
- Ocelot(四)- 认证与授权
Ocelot(四)- 认证与授权 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10932805.html 源码地址:http ...
- .frm和.ibd恢复数据
昨日晚上开发告诉我不小心truncate两个表的数据,要求还原.结果在阿里云上找到了备份内容,结果是物理备份文件.frm..ibd.心中一万个草泥马啊..没办法,开始还原吧. 1.查看测试机Mysql ...
- 图解linux安装hadoop
安装步骤: 一.准备工作 1.解压文件 [root@localhost soft]# tar -zxvf hadoop-2.4.1.tar.gz 2.改名: [root@localhost soft] ...
- 洛谷P3792 由乃与大母神原型和偶像崇拜
P3792 由乃与大母神原型和偶像崇拜 题目背景 由乃最近没事干,去研究轻拍学去了 就是一个叫做flip flappers,轻拍翻转小膜女的番 然后研究的过程中她看到了一个叫做大母神原型的东西 大母神 ...