1 通过JNI混合使用Java和C++ -----> 操作字符串
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
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);
}
}

// Prompt.h
/* 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[];
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, );
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[], outbuf[];
int len = env->GetStringUTFLength(prompt);
env->GetStringUTFRegion(prompt, , len, outbuf);
std::cout << outbuf; std::cin.get(inbuf, );
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 |
2> JNI字符串函数
|
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 |
1 通过JNI混合使用Java和C++ -----> 操作字符串的更多相关文章
- 2 通过JNI混合使用Java和C++ -----> 访问数组
关于c和cpp实现native方法的一些注释: 1> 在jni.h中首先定义了C的实现方式,然后用内联函数实现了Cpp的实现方式,如下所示: const char* GetStringUTFC ...
- android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )
JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...
- Android 通过 JNI 访问 Java 字段和方法调用
在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型.字符串和数组的相关操作,并描述了 Java 和 Native 在类型和签名之间的转换关系. 有了之前那些基础,就可以实现 Jav ...
- 【详解】JNI(Java Native Interface)(一)
前言: 一提到JNI,多数编程者会下意识地感受到一种无法言喻的恐惧.它给人的第一感觉就是"难",因为它不是单纯地在JVM环境内操作Java代码,而是跳出虚拟机与其他编程语言进行交互 ...
- Android JNI访问Java成员
在 JNI 调用中,不仅仅 Java 可以调用本地方法,本地方法也可以调用 Java 中的方法和成员变量. Java 中的类封装了属性和方法,想要访问 Java 中的属性和方法,首先要获得 Java ...
- [转]ANDROID JNI之JAVA域与c域的互操作
本文讲述AndroidJava域与C域互操作:Java域调用c域的函数:c域访问Java域的属性和方法:c域生成的对象的保存与使用.重点讲解c域如何访问Java域. 虽然AndroidJNI实现中,c ...
- JNI(Java Native Interface)
一.JNI(Java Native Interface) 1.什么是JNI: JNI(Java Native Interface):java本地开发接口 ...
- java native interface JNI 调用Java方法
在上一篇文章中介绍了JNI.以及java调用JNI.这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你能够创建Java对象,get.set 静态(static)和 实例(instanc ...
- Java Spring mvc 操作 Redis 及 Redis 集群
本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html 关于 Redis 集群搭建可以参考我的另一篇文章 Redis集群搭建与简单使用 R ...
随机推荐
- 使用ngin的静态文件下载
1,主配置文件nginx.xml #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error. ...
- 【HTML/XML 10】XML文档中的Schema文件
导读:DTD是对XML文档进行有效性验证的方法之一,事实上,继DTD之后,出现了用来规范和描述XML文档的第二代标准:Schema.Schema是DTD的继承,但是也有其不同的地方,它是真正的以独立的 ...
- javascript计算两个时间差
其实,javascript计算时间差的方式非常简单,如果是默认的Date()类型,直接相减就是相差的毫秒数. var d1 = new Date('2016/03/28 10:17:22'); var ...
- (笔记)angular 包含关系的controller参数传递
- 数据库连接池问题 Max Pool Size
摘自: http://blog.csdn.net/chensirbbk/article/details/6225268 Timeout expired 超时时间已到. 达到了最大池大小 错误及Max ...
- storm学习-storm入门
超好资料: 英文:https://github.com/xetorthio/getting-started-with-storm/blob/master/ch03Topologies.asc 中文:h ...
- Becoming a Hacker...
This is my dream... http://catb.org/~esr/faqs/hacker-howto.html 黑客的精神 世上仍有大量迷人的事情等待解决 同样的问题不应被重复处理两次 ...
- 高仿QQ的即时通讯应用带服务端软件安装
Android 基于xmpp协议,smack包,openfire服务端(在下面)的高仿QQ的即时通讯实现.实现了注册,登录,读取好友列表,搜索好友,添加分组,添加好友,删除好友,修改心情,两个客户端之 ...
- 音乐社交APP源码 V1.1
1.关于音乐曲库,对接的是百度音乐,会自动随搜索链接百度曲库2.便捷聊天,采用xmpp基本架构.3.加入和整理了群聊天.4.分布式聊天,喜欢该专辑直接进入聊天,喜欢该音乐的进入聊天.5.采用兴趣社交和 ...
- POJ C程序设计进阶 编程题#1:分配病房
编程题#1:分配病房 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 某个科 ...