C/C++调用Java代码 创建对象、字符串操作

back>>

1. java对象的创建的步骤
    - 函数NewObject可以创建java对象
    - 用GetMethodID方法取得构造方法的jmethodID,传入方法名称设定为"<init>"表示取的是构造方法的methodID
    - 构造方法的方法返回值类型的签名始终为Void
    - 例子:

    TestNative.java

package video1;

import java.util.Date;

public class TestNative {
	public int number = 100;

	public int signTest(int i, Date date, int[] arr) {
		System.out.println("Sign Test");
		return 0;
	}
	public TestNative() {
		System.out.println("Default Constructor!");
	}
	public TestNative(int i, int j) {
		this.number = i;
		System.out.println("TestNative Constructor: i:" + i);
	}

	// native关键字修饰的方法,其内容是C/C++编写的,java中不必为它编写具体的实现
	public native void sayHello();

	public static void main(String[] args) {
		System.loadLibrary("NativeCode");
		TestNative tn = new TestNative();
		tn.sayHello();
	}
}

     C/C++代码片段:

    //找到class
    jclass clazz_Kong=env->FindClass("video1/TestNative");
    //获得构造函数ID
    jmethodID MID_Kong=env->GetMethodID(clazz_Kong,"<init>","(II)V");
    //生成对象 最后两个参数是构造函数的参数,可以不写
    jobject obj_Kong = env->NewObject(clazz_Kong,MID_Kong,1999l,2l);

    //调用属性
    jfieldID Kong_num = env->GetFieldID(clazz_Kong,"number","I");
    jint numberKong= env->GetIntField(obj_Kong,Kong_num); 
    cout<<"Kong:"<<numberKong<<endl;

     - 另一种方法 AllocObject(不常用)


2. 在C/C++本地代码中访问JAVA的String字符串对象
    - 在java中,使用的字符串String对象不论是中文还是英文符号,一个字符总是占两个字节
    - java通过JNI接口可以将java的字符串转换到C/C++中的宽字符串(wchar_t*),或是传回一个UTF-8的字符串(char*)到C/C++.
    - 反过来,C/C++可以通过一个宽字符串,或是一个UTF-8编码的字符串来创建一个java端的String对象

    - 函数GetStringChars   GetStringUTFChars
      这两个函数用来取得某个jstring对象相关的Java字符串。
      分别可以取得UTF-16编码的宽字符串(jchar*)跟UTF-8编码的字符串(char*)。
      例如:
      const jchar* GetStringChars(jstring str,jboolean* copied)
      const char* GetStringUTFChars(jstirng str,jboolean* copied)
      第一个参数传入一个指向java中的String对象的jstring变量,第二个参数传入一个jboolean的指针,是用来标识是否对java的String对象进行了拷贝。如果传入这个jboolean指针不是NULL,则它会给该指针所指向的内存传入JNI_TRUE或JNI_FALSE标识是否进行了拷贝。传入NULL表示不关心是否拷贝字符串,它就不会给jboolean*指向的内存赋值
      这两个函数分别都会有两个不同的动作:
      1.开新内存,然后把java中的string拷贝到这个内存中,然后返回指向这个内存地址的指针
      2.直接返回指向java中String内存的指针,这个时候千万不要改变这个内存的内容,这将破坏String在java中始终是常量这个原则。   
      使用这两个函数取得的字符串,在不使用的时候,要使用ReleaseStringChars/ReleaseStringUTFChars来释放拷贝的内容,或是释放对java的String对象的引用
      ReleaseStringChars(jstring jstr,const jchar * str);
      ReleaseStringUTFChars(jstring jstr,const char * str);
      第一个参数指定一个jstring变量,即是要释放的本地字符串的来源,第二个参数就是要释放的本地字符串


    - 函数GetStringCritical
      为了增加直接传回指向java字符串的指针的可能性(而不是拷贝),JDK1.2出来了新的函数

      GetStringCritical/ReleaseStringCritical.
      在GetStringCritical/ReleaseStringCritical之间是一个关键区,在关键区千万不要出现中断操作,或是在JVM中分配任何新对象,否则会造成JVM死锁
      虽说这个函数会增加直接传回指向java字符串指针的可能性,不过还是会根据实际情况传回拷贝过的字符串
      不支持GetStringUTFCritical

    - 函数GetStringRegion/GetStringUTFRegion
      动作:把java字符串的内容直接拷贝到C/C++的字符数组中。在呼叫这个函数之前必须有一个C/C++分配出来的字符串,然后传入到这个函数中进行字符串的拷贝(此函数不分配内存)
      例子:
      //拷贝Java字符串并以UTF-8编码传入buffer
      GetStringUTFRegion(jstring str,jsize start,jsize len,char* buffer);
      //拷贝java字符串并以UTF-16编码传入buffer
      GetStringRegion(jstring str, jsize start,jsize len,jchar* buffer);



3. 在C/C++本地代码中创建JAVA的String字符串对象

    - 函数

    jstring NewString(const jchar* str,jsize len);
    jstring NewStringUTF(const char * str);
    //取得字符串的长度
    jsize GetStringLength(jstring str);
    jsize GetStringUTFLength(jstring str);

4. 字符串操作完整示例

    TestNative1.java

package video1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class TestNative1 {

	public String message = null;

	public native void callCppFunction();

	public static void main(String[] args) throws IOException {
		System.loadLibrary("NativeCode");
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				System.in));
		String str = reader.readLine();
		TestNative1 obj = new TestNative1();

		obj.message = str;
		obj.callCppFunction();
		System.out.println("java output:" + obj.message);
	}
}

     cpp.cpp

#include "video1_TestNative1.h"
#include "windows.h"
#include <iostream>
using namespace std;

JNIEXPORT void JNICALL Java_video1_TestNative1_callCppFunction(JNIEnv * env, jobject obj){
	
	jclass native_clazz = env->GetObjectClass(obj);
	//得到jfieldID
	jfieldID fieldID_msg = env->GetFieldID(native_clazz,"message","Ljava/lang/String;");

	//得到java字符串
	jstring j_msg =(jstring) env->GetObjectField(obj,fieldID_msg);
	//将java字符串转换为本地字符串
	const jchar * jstr = env->GetStringChars(j_msg,NULL);
	MessageBoxW(NULL,(const wchar_t*)jstr,L"Title",MB_OK);//对话框弹出
	env->ReleaseStringChars(j_msg,jstr);//释放资源
	//修改字符串
}
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值