1 通过JNI混合使用Java和C++ -----> 操作字符串
2015-06-22 12:38
751 查看
JNI(Java Native Interface)是Java语言的一部分,可以访问非Java语言编写的程序,也可以用于在C++程序中执行Java代码。
步骤:
1> 编写带有native声明方法的Java类,并且该方法只定义不实现,后期由c++负责实现:
// HelloCpp.java
public class HelloCpp
{
// ...
public native void callCpp();
// ...
}
2> 由于后期的C++实现代码最终会被编译为一个动态库.dll,因此需要在Java类中定义一个静态代码块,提前加载该动态库,假设动态的名字为hellocpp.dll:
// HelloCpp.java
public class HelloCpp
{
static
{
System.loadLibrary("hellocpp");
}
public native void callCpp();
// ...
}
3> 在Java类中定义main方法调用该native方法:
// HelloCpp.java
public class HelloCpp
{
static
{
System.loadLibrary("hellocpp");
}
public native void callCpp();
public static void main(String[] args)
{
System.out.println("***** JNI Test *****");
HelloCpp instance = new HelloCpp();
instance.callCpp(); // 调用native方法
}
}
4> 编译包含native方法的Java类,生成class字节码文件:
javac HelloCpp.java // 生成HelloCpp.class
5> 生成与native方法对应的.h头文件:
javah –jni HelloCpp // 生成HelloCpp类对于的头文件HelloCpp.h
// HelloCpp.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloCpp */
#ifndef _Included_HelloCpp
#define _Included_HelloCpp
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloCpp
* Method: callCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this);
#ifdef __cplusplus
}
#endif
#endif
6> 使用C++实现native方法:
// HelloCpp.cpp
#include "HelloCpp.h"
#include <jni.h>
#include <iostream>
JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this)
{
std::cout << "C++ Implementation" << std::endl;
}
7> 编译生成动态库hellocpp.dll:
g++ -Wl,--kill-at –shared –I D:\jdk1.7.0_75\include –I D:\jdk1.7.0_75\include\win32 HelloCpp.cpp –o hellocpp.dll
8> 调用hellocpp.dll来运行Java程序:
Java HelloCpp
结果如下:
***** JNI Test *****
C++ Implementation
说明:
JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this);
JNIWXPORT和JNICALL是宏。
JNIEnv*指向一个位置,该位置包含一个指向函数表的指针,表中的每一项都是一个指向JNI函数的指针,native方法通过JNI函数访问JVM的中的数据 ,如下所示:
第二个参数对于非静态方法为jobject,对于静态方法为jclass。jobject表示调用native方法对象自身的引用,如同C++中的this指针;jclass表示定义native方法的类的引用。
如下介绍带有参数和返回值的native方法:
// Prompt.java
[b]// Prompt.h[/b]
// Prompt.cpp
补充信息:
:: UTF-8字符串以’\0’结尾,而Unicode字符串则不是。如果需要获得Unicode格式的jstring的长度,可以使用GetStringLength;如果需要获得UTF-8格式的jstring的长度,可以先使用GetStringUTFChars,在其结果上使用strlen,或者直接使用GetStringUTFLength。
:: GetStringUTFChars的第二个参数为jboolean *isCopy,其指向分配的内存空间,如果isCopy被设为JNI_TRUE,那么返回的String是Java String的一个副本;如果被设为JNI_FALSE,那么返回一个指向Java String本身的指针,此时不允许修改返回的String。
:: 函数对Get/ReleaseStringCritical的作用于Get/ReleaseStringChars类似,但是对于程序员而言,该函数对之间的代码相当于“临界区”。在该“临界区”内,native代码不能调用任何的JNI函数,否则将引起当前线程阻塞。
:: GetStringRegion/GetStringUTFRegion将Unicode格式的String复制到预分配的缓冲区中,由于不需要JVM分配内存,因此也就不需要释放操作:
总结:
1> 数据类型对应关系表:
2> JNI字符串函数
步骤:
1> 编写带有native声明方法的Java类,并且该方法只定义不实现,后期由c++负责实现:
// HelloCpp.java
public class HelloCpp
{
// ...
public native void callCpp();
// ...
}
2> 由于后期的C++实现代码最终会被编译为一个动态库.dll,因此需要在Java类中定义一个静态代码块,提前加载该动态库,假设动态的名字为hellocpp.dll:
// HelloCpp.java
public class HelloCpp
{
static
{
System.loadLibrary("hellocpp");
}
public native void callCpp();
// ...
}
3> 在Java类中定义main方法调用该native方法:
// HelloCpp.java
public class HelloCpp
{
static
{
System.loadLibrary("hellocpp");
}
public native void callCpp();
public static void main(String[] args)
{
System.out.println("***** JNI Test *****");
HelloCpp instance = new HelloCpp();
instance.callCpp(); // 调用native方法
}
}
4> 编译包含native方法的Java类,生成class字节码文件:
javac HelloCpp.java // 生成HelloCpp.class
5> 生成与native方法对应的.h头文件:
javah –jni HelloCpp // 生成HelloCpp类对于的头文件HelloCpp.h
// HelloCpp.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloCpp */
#ifndef _Included_HelloCpp
#define _Included_HelloCpp
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloCpp
* Method: callCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this);
#ifdef __cplusplus
}
#endif
#endif
6> 使用C++实现native方法:
// HelloCpp.cpp
#include "HelloCpp.h"
#include <jni.h>
#include <iostream>
JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this)
{
std::cout << "C++ Implementation" << std::endl;
}
7> 编译生成动态库hellocpp.dll:
g++ -Wl,--kill-at –shared –I D:\jdk1.7.0_75\include –I D:\jdk1.7.0_75\include\win32 HelloCpp.cpp –o hellocpp.dll
8> 调用hellocpp.dll来运行Java程序:
Java HelloCpp
结果如下:
***** JNI Test *****
C++ Implementation
说明:
JNIEXPORT void JNICALL Java_HelloCpp_callCpp(JNIEnv* env, jobject this);
JNIWXPORT和JNICALL是宏。
JNIEnv*指向一个位置,该位置包含一个指向函数表的指针,表中的每一项都是一个指向JNI函数的指针,native方法通过JNI函数访问JVM的中的数据 ,如下所示:
第二个参数对于非静态方法为jobject,对于静态方法为jclass。jobject表示调用native方法对象自身的引用,如同C++中的this指针;jclass表示定义native方法的类的引用。
如下介绍带有参数和返回值的native方法:
// Prompt.java
class Prompt { static { System.loadLibrary("Prompt"); } private native String GetLine(String prompt); public static void main(String[] args) { Prompt p = new Prompt(); String input = p.GetLine("Enter a line:"); System.out.println("Your Input is: " + input); } }
[b]// Prompt.h[/b]
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class Prompt */ #ifndef _Included_Prompt #define _Included_Prompt #ifdef __cplusplus extern "C" { #endif /* * Class: Prompt * Method: GetLine * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt); #ifdef __cplusplus } #endif #endif
// Prompt.cpp
#include "Prompt.h" #include <iostream> JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt) { char buf[1024]; const char* str; str = env->GetStringUTFChars(prompt, NULL); /* 获得传入的字符串,将其转换为native Strings */ if(str == NULL) /* str == NULL意味着JVM为native String分配内存失败 */ { return NULL; } std::cout << str; /* 显示传入的字符串参数 prompt */ env->ReleaseStringUTFChars(prompt, str); /* 通知JVM释放String所占的内存 */ std::cin.get(buf, 1024); return env->NewStringUTF(buf); /* 构造新的Java.lang.String,如果JVM分配内存失败,则抛出OutOfMemoryError,并且返回NULL */ }
补充信息:
:: UTF-8字符串以’\0’结尾,而Unicode字符串则不是。如果需要获得Unicode格式的jstring的长度,可以使用GetStringLength;如果需要获得UTF-8格式的jstring的长度,可以先使用GetStringUTFChars,在其结果上使用strlen,或者直接使用GetStringUTFLength。
:: GetStringUTFChars的第二个参数为jboolean *isCopy,其指向分配的内存空间,如果isCopy被设为JNI_TRUE,那么返回的String是Java String的一个副本;如果被设为JNI_FALSE,那么返回一个指向Java String本身的指针,此时不允许修改返回的String。
:: 函数对Get/ReleaseStringCritical的作用于Get/ReleaseStringChars类似,但是对于程序员而言,该函数对之间的代码相当于“临界区”。在该“临界区”内,native代码不能调用任何的JNI函数,否则将引起当前线程阻塞。
:: GetStringRegion/GetStringUTFRegion将Unicode格式的String复制到预分配的缓冲区中,由于不需要JVM分配内存,因此也就不需要释放操作:
JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt) { char inbuf[1024], outbuf[1024]; int len = env->GetStringUTFLength(prompt); env->GetStringUTFRegion(prompt, 0, len, outbuf); std::cout << outbuf; std::cin.get(inbuf, 1024); return env->NewStringUTF(inbuf); }
总结:
1> 数据类型对应关系表:
Java 类型 | 本地 C 类型 | 实际表示的 C 类型(Win32) |
boolean | jboolean | unsigned char |
byte | jbyte | signed char |
char | jchar | unsigned short |
short | jshort | short |
int | jint | long |
long | jlong | __int64 |
float | jfloat | float |
double | jdouble | double |
void | void | N/A |
JNI函数 | 描述 | 版本 |
GetStringChars ReleaseStringChars | 获得/释放一个Unicode格式的字符串指针,可能返回一个字符串的副本 | JDK 1.1 |
GetStringUTFChars ReleaseStringUTFChars | 获得/释放一个UTF-8格式的字符串指针,可能返回一个字符串的副本 | JDK 1.1 |
GetStringLength | 返回Unicode格式字符串的长度 | JDK 1.1 |
GetStringUTFLength | 返回UTF-8格式字符串的长度 | JDK 1.1 |
NewString | 根据Unicode格式的C字符串创建一个Java字符串 | JDK 1.1 |
NewStringUTF | 根据UTF-8格式的C字符串创建一个Java字符串 | JDK 1.1 |
GetStringCritical ReleaseStringCritical | 获得/释放一个Unicode格式的字符串指针,可能返回一个字符串的副本【在该函数对区间内,不能使用任何JNI函数】 | JDK 1.2 |
GetStringRegion | 将Unicode格式的String复制到预分配的缓冲区中 | JDK 1.2 |
GetStringUTFRegion | 将UTF-8格式的String复制到预分配的缓冲区中 | JDK 1.2 |
相关文章推荐
- 输出以下图案
- c++使用流迭代器istream_iterator和ostream_iterator
- C语言学习笔记(六)——其他编程知识
- C语言学习笔记(五)——指针【C语言的灵魂】
- C语言(2)数据类型、常量、Printf、sizeof、scanf的使用
- C++函数模板
- C++类构造函数初始化列表,子类向父类传参数
- c++ 子类调用父类有参构造函数
- C语言学习笔记(四)——函数(重点)
- 转载:c++ sort用法
- 用二分法求下面方程在(-10,10)之间的根:2x^3-4x^2+3x-6=0
- c++中的explicit
- C++ new A和new A()的区别详解
- c++ auto_ptr(memory)
- Effective C++ 条款9
- 【读书笔记:C++ primer plus 第六版 中文版】第5章 循环和关系表达式
- 中国大学MOOC-翁恺-C语言程序设计习题集 题目号03-1 Source code
- c语言头文件存在的合理性
- VC++中subclassdlgitem函数的功能、用法及注意事项
- 中国大学MOOC-翁恺-C语言程序设计习题集 题目号03-0 Source code