Java使用JNI调用C++的完整流程
2015-01-09 16:37
369 查看
JNI其实是Java NativeInterface的简称,也就是java本地接口。它提供了若干的API实现了和Java和其他语言的通信(主要是C/C++)。
Java以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决Java对本地操作的一种方法就是JNI。
Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。
在项目中管理很好一般可以不使用JNI,但是有时候必须用到的时候就要掌握一下这个东西了。其实Java很多的源码里面的一些算法都是Native声明的,也就是这些方法很可能是在C/C++中实现了的。
我没事做的时候自己单独重新做了一遍JNI使用过程,分享一下流程。
1. 首先在Eclipse建立一个Java类,在这个类中用native关键字声明需要用到的函数
下面是我自己写的测试代码
package com.ghgame.javausecpp;
public class JavaUseCpp {
public JavaUseCpp() {
System.out.println(">>>>>JNI Test Start<<<<<");
}
static {
}
public native void printStr(String str);
}
2. 在DOS窗口下生产C++的h文件
这里使用命令来完成
去找到Eclipse新建的工程目录下的bin文件夹,bin存放编译好的class文件;
然后cd 到这个E:\WorkAndroid\JNITest\bin目录
在dos下输入命令
E:\WorkAndroid\JNITest\bin>javah-classpath . -jni com.ghgame.javausecpp. JavaUseCpp
然后在E:\WorkAndroid\JNITest\bin即可找到一个com_ghgame_javausecpp_JavaUseCpp.h头文件,生成成功!
注意:com.ghgame.javausecpp是包名,JavaUseCpp是类名
下面是生成的h文件截图:
这里javah的用法:
到这里Java部分就算是差不多了。
可以打开看看刚刚生成的这个com_ghgame_javausecpp_JavaUseCpp.h头文件
这里面注释上标注类名、方法名、签名(Signature),签名这个东西下面来说。在这里最重要的是Java_com_ghgame_javausecpp_JavaUseCpp_printStr这个方法签名。在Java端我们执行 printStr(String str)这个方法之后,JVM就会帮我们调用在DLL里的Java_com_ghgame_javausecpp_JavaUseCpp_printStr这个方法。因此我们新建一个C++source file来实现这个方法。
还是扯哈签名这个东西。
为什么会有方法签名这种东西呢?这是因为Java这边支持函数重载,即虽然参数不一样,但是方法名一样,那么在JNI层它们的方法名都会是一样的,那JNI也会犯迷糊了,得找哪个呢?
不过也正是因为其参数类型是不一样的,所以就出现了方法签名,利用方法签名和方法名来唯一确定一个JNI函数的调用。
既然方法签名是基于参数类型的不同而形成的,首先要知道Java各数据类型对应的签名是什么,也就是所谓的类型签名,
在jni.h文件中就已经定义了这样一套规则,如下:
具体不清楚的还是找度娘问其他先生。
3. 写CPP文件,编译出DLL
建项目具体步骤就不说了。
新建一个Win32Cpp就行了,里面选dll,然后把刚才编译出来的h文件复制到C++工程的根目录去
然后新建一个com_ghgame_javausecpp_JavaUseCpp.cppCpp文件
在这里面实现h文件中的方法,我这里就打印了一下Java传过来的值而已
这里编译的时候值得注意的几个问题:
a. 需要另外两个头文件
都在jdk的安装目录下,有个include文件夹,把include文件夹下面的jni.h复制到C++工程的根目录,然后把com_ghgame_javausecpp_JavaUseCpp.h文件的#include <jni.h>改成#include "jni.h"就行了。
还有个在include里面有个win32文件夹,jni_md.h这个头文件也复制到C++工程的根目录。
b. 在编译项目时候要注意选择平台,如果你jdk,机子都是64位你就编译64位的dll,32位同理。否则就是这个错误:JNI Can't load IA 32-bit .dll on a AMD 64-bit platform
编译出来的内容就是这样:
4. 配置Dll
这里加载的方法有两个,
a. 把刚刚生成的Dll扔到C盘Sysytem32或者SysWOW64文件夹下
b. 把C++工程下生成dll的目录设置到环境变量path中去(我是64位的机子就把x64的配置到Path去了)
这个设置看个人喜好了
5. Java加载Dll,完成
到最后一步了,在Java里面加载Dll库,调用c++实现的方法
感觉还是挺66666的。
好了,GG了,收拾东西准备下班。
Java以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决Java对本地操作的一种方法就是JNI。
Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。
在项目中管理很好一般可以不使用JNI,但是有时候必须用到的时候就要掌握一下这个东西了。其实Java很多的源码里面的一些算法都是Native声明的,也就是这些方法很可能是在C/C++中实现了的。
我没事做的时候自己单独重新做了一遍JNI使用过程,分享一下流程。
1. 首先在Eclipse建立一个Java类,在这个类中用native关键字声明需要用到的函数
下面是我自己写的测试代码
package com.ghgame.javausecpp;
public class JavaUseCpp {
public JavaUseCpp() {
System.out.println(">>>>>JNI Test Start<<<<<");
}
static {
}
public native void printStr(String str);
}
2. 在DOS窗口下生产C++的h文件
这里使用命令来完成
去找到Eclipse新建的工程目录下的bin文件夹,bin存放编译好的class文件;
然后cd 到这个E:\WorkAndroid\JNITest\bin目录
在dos下输入命令
E:\WorkAndroid\JNITest\bin>javah-classpath . -jni com.ghgame.javausecpp. JavaUseCpp
然后在E:\WorkAndroid\JNITest\bin即可找到一个com_ghgame_javausecpp_JavaUseCpp.h头文件,生成成功!
注意:com.ghgame.javausecpp是包名,JavaUseCpp是类名
下面是生成的h文件截图:
这里javah的用法:
到这里Java部分就算是差不多了。
可以打开看看刚刚生成的这个com_ghgame_javausecpp_JavaUseCpp.h头文件
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_ghgame_javausecpp_JavaUseCpp */ #ifndef _Included_com_ghgame_javausecpp_JavaUseCpp #define _Included_com_ghgame_javausecpp_JavaUseCpp #ifdef __cplusplus extern "C" { #endif /* * Class: com_ghgame_javausecpp_JavaUseCpp * Method: printStr * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_com_ghgame_javausecpp_JavaUseCpp_printStr (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif
这里面注释上标注类名、方法名、签名(Signature),签名这个东西下面来说。在这里最重要的是Java_com_ghgame_javausecpp_JavaUseCpp_printStr这个方法签名。在Java端我们执行 printStr(String str)这个方法之后,JVM就会帮我们调用在DLL里的Java_com_ghgame_javausecpp_JavaUseCpp_printStr这个方法。因此我们新建一个C++source file来实现这个方法。
还是扯哈签名这个东西。
为什么会有方法签名这种东西呢?这是因为Java这边支持函数重载,即虽然参数不一样,但是方法名一样,那么在JNI层它们的方法名都会是一样的,那JNI也会犯迷糊了,得找哪个呢?
不过也正是因为其参数类型是不一样的,所以就出现了方法签名,利用方法签名和方法名来唯一确定一个JNI函数的调用。
既然方法签名是基于参数类型的不同而形成的,首先要知道Java各数据类型对应的签名是什么,也就是所谓的类型签名,
在jni.h文件中就已经定义了这样一套规则,如下:
typedef union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; } jvalue;
具体不清楚的还是找度娘问其他先生。
3. 写CPP文件,编译出DLL
建项目具体步骤就不说了。
新建一个Win32Cpp就行了,里面选dll,然后把刚才编译出来的h文件复制到C++工程的根目录去
然后新建一个com_ghgame_javausecpp_JavaUseCpp.cppCpp文件
在这里面实现h文件中的方法,我这里就打印了一下Java传过来的值而已
#include "stdafx.h" #include "com_ghgame_javausecpp_JavaUseCpp.h" JNIEXPORT void JNICALL Java_com_ghgame_javausecpp_JavaUseCpp_printStr(JNIEnv* env, jobject obj, jstring str) { const char* pTempStr = env->GetStringUTFChars(str, NULL); printf(">>>>>>>>>>>>>>>The input string is = [ %s ]<<<<<<<<<<<<<<",pTempStr); }
这里编译的时候值得注意的几个问题:
a. 需要另外两个头文件
都在jdk的安装目录下,有个include文件夹,把include文件夹下面的jni.h复制到C++工程的根目录,然后把com_ghgame_javausecpp_JavaUseCpp.h文件的#include <jni.h>改成#include "jni.h"就行了。
还有个在include里面有个win32文件夹,jni_md.h这个头文件也复制到C++工程的根目录。
b. 在编译项目时候要注意选择平台,如果你jdk,机子都是64位你就编译64位的dll,32位同理。否则就是这个错误:JNI Can't load IA 32-bit .dll on a AMD 64-bit platform
编译出来的内容就是这样:
4. 配置Dll
这里加载的方法有两个,
a. 把刚刚生成的Dll扔到C盘Sysytem32或者SysWOW64文件夹下
b. 把C++工程下生成dll的目录设置到环境变量path中去(我是64位的机子就把x64的配置到Path去了)
这个设置看个人喜好了
5. Java加载Dll,完成
到最后一步了,在Java里面加载Dll库,调用c++实现的方法
package com.ghgame.javausecpp; public class JavaUseCpp { public JavaUseCpp() { System.out.println(">>>>>JNI Test Start<<<<<"); } // 加载生成的DLL库文件 static { System.loadLibrary("LibJniTest"); } public native void printStr(String str); public static void main(String[] args) { String cName = "Ghgame"; // 传个值试试效果 new JavaUseCpp().printStr(cName); } }下面是我执行的结果:
感觉还是挺66666的。
好了,GG了,收拾东西准备下班。
相关文章推荐
- Android JNI 使用的数据结构JNINativeMethod详解 ||建立Android SDK下的JNI、JAVA应用完整步骤---Android JAVA调用C++代码
- [JNI] Eclipse直接完成JAVA调用C/C++ (Eclipse上使用CDT结合MinGW)
- Java使用JNI调用C/C++的DLL动态链接库1
- 使用JNI进行Java与C/C++语言混合编程(2)--在C/C++中调用Java代码
- 使用JNI进行混合编程:在C/C++中调用Java代码
- [JNI] Eclipse直接完成JAVA调用C/C++ (Eclipse上使用CDT结合MinGW)
- Ubuntu下,Java中利用JNI调用codeblocks c++生成的动态库的使用步骤
- Android中简单的JNI使用,C++调用JAVA
- 使用JNI进行混合编程:在C/C++中调用Java代码
- windows7下,Java中利用JNI调用c++生成的动态库的使用步骤
- 使用JNI进行Java与C/C++语言混合编程(1)--在Java中调用C/C++本地库
- java 使用jni调用本地c++类库
- jni使用基础(八)之jni使用流程及C调用java简单说明
- 使用JNI进行Java与C/C++语言混合编程(1)--在Java中调用C/C++本地库
- [JNI] Eclipse直接完成JAVA调用C/C++ (Eclipse上使用CDT结合MinGW)
- 使用JNI,在java端调用c/c++
- Java使用JNI调用C/C++的DLL动态链接库2
- 使用JNI进行混合编程:在Java中调用C/C++本地库
- linux下使用jni实现c++调用java程序(1)准备工作
- java中如何使用JNI调用C++写的函数