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++ -----> 操作字符串的更多相关文章

  1. 2 通过JNI混合使用Java和C++ -----> 访问数组

    关于c和cpp实现native方法的一些注释: 1>  在jni.h中首先定义了C的实现方式,然后用内联函数实现了Cpp的实现方式,如下所示: const char* GetStringUTFC ...

  2. android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )

    JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...

  3. Android 通过 JNI 访问 Java 字段和方法调用

    在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型.字符串和数组的相关操作,并描述了 Java 和 Native 在类型和签名之间的转换关系. 有了之前那些基础,就可以实现 Jav ...

  4. 【详解】JNI(Java Native Interface)(一)

    前言: 一提到JNI,多数编程者会下意识地感受到一种无法言喻的恐惧.它给人的第一感觉就是"难",因为它不是单纯地在JVM环境内操作Java代码,而是跳出虚拟机与其他编程语言进行交互 ...

  5. Android JNI访问Java成员

    在 JNI 调用中,不仅仅 Java 可以调用本地方法,本地方法也可以调用 Java 中的方法和成员变量. Java 中的类封装了属性和方法,想要访问 Java 中的属性和方法,首先要获得 Java ...

  6. [转]ANDROID JNI之JAVA域与c域的互操作

    本文讲述AndroidJava域与C域互操作:Java域调用c域的函数:c域访问Java域的属性和方法:c域生成的对象的保存与使用.重点讲解c域如何访问Java域. 虽然AndroidJNI实现中,c ...

  7. JNI(Java Native Interface)

    一.JNI(Java Native Interface)        1.什么是JNI:               JNI(Java Native Interface):java本地开发接口   ...

  8. java native interface JNI 调用Java方法

    在上一篇文章中介绍了JNI.以及java调用JNI.这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你能够创建Java对象,get.set 静态(static)和 实例(instanc ...

  9. Java Spring mvc 操作 Redis 及 Redis 集群

    本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html 关于 Redis 集群搭建可以参考我的另一篇文章 Redis集群搭建与简单使用 R ...

随机推荐

  1. 操作笔记:linux下安装ftp

    1,安装ftp [root@iZ945sgm0ugZ ~]# yum install vsftpd 安装成功的信息: [root@iZ945sgm0ugZ ~]# yum install vsftpd ...

  2. 用命令实现Win7远程桌面关机和重启

    关机 shutdown -s -t 0 重启 shutdown -r -t 0 打开运行框(Win+R键),输入上述命令即可,后面的数字表示关机/重启延迟的时间 at 12:00 shutdown - ...

  3. Acronis Server备份Linux系统

    Acronis Server备份Linux系统 前段时间用Acronis Disk Director Suite解决了Thinkpad笔记本在win7的分区问题(http://chenguang.bl ...

  4. 【MySQL】MySQL索引背后的之使用策略及优化【转】

    转自:http://database.ctocio.com.cn/353/11664853.shtml 另外很不错的对于索引及索引优化的文章: http://www.cnblogs.com/magia ...

  5. HTTP协议请求方式: 中GET、POST和HEAD的介绍以及错误提示码

    HTTP协议中GET.POST和HEAD的介绍 2008-05-10 14:15 GET: 请求指定的页面信息,并返回实体主体. HEAD: 只请求页面的首部. POST: 请求服务器接受所指定的文档 ...

  6. C# 发送邮件方法2

    一. 发送邮件程序:(使用System.Web.Mail下的类) "; //SMTP服务密码 strFrom = "jailu@163.com"; //发送方邮件地址 C ...

  7. WP8__实现ListBox横向滑动及子项绑定图片等控件

    <!--实现绑定的图片等信息 ListBox水平滚动--> <Grid> <Grid.Resources> <Style x:Key="horizo ...

  8. [原]Hrbust1328 相等的最小公倍数 (筛素数,素因子分解)

    本文出自:http://blog.csdn.net/svitter/ 题意: 求解An 与 An-1是否相等. n分为两个情况-- 1.n为素数, 2.n为合数. =  =好像说了个废话..素数的时候 ...

  9. makefile中的target到底代表什么?

    刚开始用make的时候,以为makefile中名字叫做main的target就是make默认执行的target(中文翻译叫做标的(di,四声),下面统一称呼为标的),然后曾经很天真地犯过这样的错误,就 ...

  10. POJ C++程序设计 编程题#3 编程作业—文件操作与模板

    编程题#3: 整数的输出格式 来源: POJ(Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 1000kB 描述 利 ...