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

 1 class Prompt
 2 {
 3     static
 4     {
 5         System.loadLibrary("Prompt");
 6     }
 7     private native String GetLine(String prompt);
 8
 9     public static void main(String[] args)
10     {
11         Prompt p = new Prompt();
12         String input = p.GetLine("Enter a line:");
13         System.out.println("Your Input is: " + input);
14     }
15 }

    

// Prompt.h

 1 /* DO NOT EDIT THIS FILE - it is machine generated */
 2 #include <jni.h>
 3 /* Header for class Prompt */
 4
 5 #ifndef _Included_Prompt
 6 #define _Included_Prompt
 7 #ifdef __cplusplus
 8 extern "C" {
 9 #endif
10 /*
11  * Class:     Prompt
12  * Method:    GetLine
13  * Signature: (Ljava/lang/String;)Ljava/lang/String;
14  */
15 JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt);
16
17 #ifdef __cplusplus
18 }
19 #endif
20 #endif

// Prompt.cpp

 1 #include "Prompt.h"
 2 #include <iostream>
 3
 4 JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt)
 5 {
 6     char buf[1024];
 7     const char* str;
 8     str = env->GetStringUTFChars(prompt, NULL);            /* 获得传入的字符串,将其转换为native Strings */
 9     if(str == NULL)                                        /* str == NULL意味着JVM为native String分配内存失败 */
10     {
11         return NULL;
12     }
13     std::cout << str;                                        /* 显示传入的字符串参数 prompt */
14     env->ReleaseStringUTFChars(prompt, str);                /* 通知JVM释放String所占的内存 */
15
16     std::cin.get(buf, 1024);
17     return env->NewStringUTF(buf);                        /* 构造新的Java.lang.String,如果JVM分配内存失败,则抛出OutOfMemoryError,并且返回NULL */
18 }

补充信息:

:: 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 JNIEXPORT jstring JNICALL Java_Prompt_GetLine(JNIEnv* env, jobject _this, jstring prompt)
 2 {
 3     char inbuf[1024], outbuf[1024];
 4     int len = env->GetStringUTFLength(prompt);
 5     env->GetStringUTFRegion(prompt, 0, len, outbuf);
 6     std::cout << outbuf;
 7
 8     std::cin.get(inbuf, 1024);
 9     return env->NewStringUTF(inbuf);
10 }

总结:

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

时间: 2024-11-05 18:49:32

1 通过JNI混合使用Java和C++ -----> 操作字符串的相关文章

2 通过JNI混合使用Java和C++ -----&gt; 访问数组

关于c和cpp实现native方法的一些注释: 1>  在jni.h中首先定义了C的实现方式,然后用内联函数实现了Cpp的实现方式,如下所示: const char* GetStringUTFChars(jstring str, jboolean *isCopy)   /* 依赖于C方式实现Cpp */ { return functions->GetStringUTFChars(this,str,isCopy);       /* C实现方式 */ } 因此,在C中可能这样写:(*env)-&

java native interface JNI 调用Java方法

在上一篇文章中介绍了JNI,以及java调用JNI,这篇讲一下 JNI调用java方法. 通过使用合适的JNI函数,你可以创建Java对象,get.set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数.JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数. 下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数.每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对

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

JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类库无法满足要求,且在数学运算,实时渲染的游戏上,音视频处理等方面上与C/C++相比效率稍低. 然后,Java语言无法直接操作硬件,C/C++代码不仅能操作硬件而且还能发挥硬件最佳性能. 接着,使用Java调用本地的C/C++代码所写的库,省去了重复开发的麻烦,并且可以利用很多开源的库提高程序效率.

Cocos2d-x3.3RC0通过JNI实现Java与C++互调

一.JNI JNI(Java Native Interface):Java的本地调用.本文通过JNI在Cocos2d-x3.3RC0中完成Java与C++的互调.具体实现以下两个功 能:(1)通过Android sdk的API得到应用程序的包名,并传递给C++层函数.(2)通过C++函数调用Android的Java层函数,显示一个对话框.点击按钮退出程序. 详细知识见:http://blog.csdn.net/yuxikuo_1/article/details/39577257.其中最重要的是J

JAVA使用和操作properties文件

java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式,在properties文件中,可以用"#"来作注释,properties文件在Java编程中用到的地方很多,操作很方便.Properties 类存在于包 Java.util 中,该类继承自 Hashtable. 1. getProperty ( String  key) ,   用指定的键在此属性列表中搜索

java 常用Date操作

[java] view plain copy 获取年月日时分秒: [java] view plain copy package com.util; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; public class Test { public void getTimeByDate(){ Date date = new Date(); DateFormat df1 = DateFor

ndk学习17: jni之Java调用C&C++

一.Hello World 1. 定义函数原型 native关键字定义的函数即为jni函数 2.生成头文件 切换到src目录执行: (这个过程可以写脚本自动完成,比如自动拷贝到jni目录) javah -jni 包名.类名 在根目录下生成: org_bing_testjni_MainActivity.h 3. 工程中添加jni代码 工程右键->添加native code->输入名字->finish 多了如下文 新建一个Application.mk,配置相关选项(详细查看ndk有关Appl

Error loading RS jni library: java.lang.UnsatisfiedLinkError 解决方案

我们可能会用到模糊效果,就会想到renderscript.jar , 但是模糊效果是3.0以后的效果,在有的4.x以上的手机上也会造成错误,Error loading RS jni library: java.lang.UnsatisfiedLinkError,会报出这样的错误,明显是手机上没有.so包. 错误图示 明显可以得出,没有.librsjni.so的包存在,那么要怎么处理呢,其实在sdk中已经提供了相应的.so库.我们只要找到即可,然后放入libs下即可 这样在任何机型上都不会报错了,

Java 文件写操作

在进行文件写操作的时候,有两种操作方方式.一个是连续写,一个是覆盖式写. 代码如下: import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; // text:要写入的内容:isAppend:写入方式,true为连续写,false为覆盖式写入. public void write(String text