`
hm4123660
  • 浏览: 282411 次
  • 性别: Icon_minigender_1
  • 来自: 广州
博客专栏
Dea4ce76-f328-3ab2-b24a-fb268e1eeb75
数据结构
浏览量:69994
社区版块
存档分类
最新评论

jni创建java对象

    博客分类:
  • JNI
阅读更多

            在本地方法实现代码中创建java对象,其中还主要涉及到jni和java之间中文字符串的的乱码问题。

 

1.创建java对象

首先在java端自定义一个Person类如下

package com.example;

public class Person {
	
	public String name;
	
	public int age;
	
	public Person()
	{
		
	}
	public Person(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
	

	public void Desc()
	{
		System.out.println("姓名: "+this.name+" 年龄:"+this.age);
	}
	

}

 定义本地方法sayHello方法,在sayHello方法里实现创建Person对象,并调用创建对象的Desc()方法

package com.example;


public class jni_test {

	//在本地方法sayHello里里创建Person对象
	public native void sayHello();
	

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

 

jni中创建java对象需要使用NewObject方法,jni里定义构造函数的名称为<init>,返回值为Void

 

1.调用默认构造函数创建Person对象

JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)
{
	//获取java的Class
	jclass my_class=evn->FindClass("com/example/Person");
	//获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void
	jmethodID init_id=evn->GetMethodID(my_class,"<init>","()V");//(类,属性名.签名)
	//创建Person对象--使用NewObject方法
	jobject person=evn->NewObject(my_class,init_id);
 	//为person赋值
	jfieldID name_id=evn->GetFieldID(my_class,"name","Ljava/lang/String;");
  	evn->SetObjectField(person,name_id,(evn)->NewStringUTF("mike"));
	
	jfieldID age_id=evn->GetFieldID(my_class,"age","I");
 	evn->SetIntField(person,age_id,20);
	
	//获取Person的Desc方法id
	 jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");

	 //调用创建的person里的desc方法
 	evn->CallVoidMethod(person,desc_id);
	
}

 运行结果:



 

2.调用有参构造方法,构造对象时完成对象属性赋值

 

JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)
{
	//获取java的Class
	jclass my_class=evn->FindClass("com/example/Person");
	//获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void
	jmethodID init_id=evn->GetMethodID(my_class,"<init>","(Ljava/lang/String;I)V");//(类,属性名.签名)	

	//创建Person对象--使用NewObject方法
	jobject person=evn->NewObject(my_class,init_id, (evn)->NewStringUTF("mike"),20);
	
	//获取Person的Desc方法id
	 jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");

	 //调用创建的person里的desc方法
 	evn->CallVoidMethod(person,desc_id);
	
}

 运行结果:



 

2.jni和java中文乱码

如果把创建Person对象改为

     jobject person=evn->NewObject(my_class,init_id, (evn)->NewStringUTF("珍奇异"),20)

 

此时运行结果产生了中文乱码:



 

乱码产生原因

java内部是使用16bit的unicode编码(UTF-16)来表示字符串的,无论中文英文都是2字节;jni内部是使用UTF-8编码来表示字符串的,UTF-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;

 

1、java --> c/c++

这种情况中,java调用的时候使用的是UTF-16编码的字符串,jvm把这个字符串传给jni,c/c++得到的输入是jstring,这个时 候,可以利用jni提供的两种函数,一个是GetStringUTFChars,这个函数将得到一个UTF-8编码的字符串;另一个是 GetStringChars这个将得到UTF-16编码的字符串。

 

2、c/c++ --> java

jni返回给java的字符串,c/c++首先应该负责把这个字符串变成UTF-8或者UTF-16格式,然后通过NewStringUTF或者NewString来把它封装成jstring,返回给java就可以了。

 

解决方法

方法一:使用#include <windows.h>头文件函数

导入头文件#include <windows.h>  ,此时有利用两个函数来处理字符串

//将jstring类型转换成windows类型
char* jstringToWindows( JNIEnv  *env, jstring jstr )
{
    int length = (env)->GetStringLength(jstr );
    const jchar* jcstr = (env)->GetStringChars(jstr, 0 );
    char* rtn = (char*)malloc( length*2+1 );
    int size = 0;
    size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
    if( size <= 0 )
        return NULL;
    (env)->ReleaseStringChars(jstr, jcstr );
    rtn[size] = 0;
    return rtn;
}
//将windows类型转换成jstring类型
jstring WindowsTojstring( JNIEnv* env, char* str )
{
    jstring rtn = 0;
    int slen = strlen(str);
    unsigned short * buffer = 0;
    if( slen == 0 )
        rtn = (env)->NewStringUTF(str ); 
    else
    {
        int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
        buffer = (unsigned short *)malloc( length*2 + 1 );
        if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
            rtn = (env)->NewString(  (jchar*)buffer, length );
    }
    if( buffer )
        free( buffer );
    return rtn;
}

 

此时把本地完整代码为:

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

//将windows类型转换成jstring类型
jstring WindowsTojstring( JNIEnv* env, char* str )
{
    jstring rtn = 0;
    int slen = strlen(str);
    unsigned short * buffer = 0;
    if( slen == 0 )
        rtn = (env)->NewStringUTF(str ); 
    else
    {
        int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
        buffer = (unsigned short *)malloc( length*2 + 1 );
        if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
            rtn = (env)->NewString(  (jchar*)buffer, length );
    }
    if( buffer )
        free( buffer );
    return rtn;
}


JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)
{
	//获取java的Class
	jclass my_class=evn->FindClass("com/example/Person");
	//获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void
	
	jmethodID init_id=evn->GetMethodID(my_class,"<init>","(Ljava/lang/String;I)V");//(类,属性名.签名)	
	//创建Person对象--使用NewObject方法
	jobject person=evn->NewObject(my_class,init_id, WindowsTojstring(evn,"珍奇异"),20);
	
	
	//获取Person的Desc方法id
	jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");

	//调用创建的person里的desc方法
	evn->CallVoidMethod(person,desc_id);
	
}

 运行结果:



 

方法二:

完整c++代码:

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

//检查是否含有中文
int isASCII(const char * chp)
{
	char ch;
	jboolean flag= 1;
	while(ch = *chp++){
		if(ch & 0x80){
			flag = 0;
			break;
		}
	}
	return flag;
}

//jstring to char*
char* JstringToPchar(JNIEnv* env, jstring jstr, const char * encoding,jmethodID gmidStringGetBytes)
{
	char* rtn = NULL;
	jstring jencoding;
	jencoding=(env)->NewStringUTF(encoding);       
	jbyteArray barr= (jbyteArray)(env)->CallObjectMethod(jstr, gmidStringGetBytes, jencoding);   
	jsize alen = (env)->GetArrayLength(barr);
	jbyte* ba = (env)->GetByteArrayElements(barr, JNI_FALSE);
	if (alen > 0)
	{
		rtn = (char*)malloc( alen + 1);   
		memcpy(rtn, ba, alen);
		rtn[alen] = 0;
	}
	(env)->ReleaseByteArrayElements(barr, ba, 0);
	return rtn;
}

//char* to jstring
jstring PcharToJstring(JNIEnv* env, const char* pchar,const char * encoding,jclass gStringClass,jmethodID gmidStringInit)
{
	jstring jencoding;
	jbyteArray bytes = (env)->NewByteArray(strlen(pchar));
	env->SetByteArrayRegion(bytes, 0, strlen(pchar), (jbyte*)pchar);
	jencoding = env->NewStringUTF(encoding);
	return (jstring)(env)->NewObject(gStringClass, gmidStringInit, bytes, jencoding);

}

JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)
{
	//获取java的Class
	jclass my_class=evn->FindClass("com/example/Person");
	
	//获取java的String相关方法
	jclass str_class=evn->FindClass("java/lang/String");
	jmethodID Byte_id=evn->GetMethodID(str_class,"getBytes", "(Ljava/lang/String;)[B");
	jmethodID Strinit_id=evn->GetMethodID(str_class,"<init>","([BLjava/lang/String;)V");

	//生成防止乱码字符串--结果赋给result
	char *myTest = "珍奇异";
	jstring result;
	//没有中文的情况
	if(isASCII(myTest)) {
		result = evn->NewStringUTF(myTest);
	} 
	else{
		result = PcharToJstring(evn,myTest,"gbk",str_class,Strinit_id);
		char *outbuf;
		outbuf = JstringToPchar(evn,result,"utf-8",Byte_id);
		result =  (evn)->NewStringUTF(outbuf);
		if(outbuf){
			free(outbuf);
		}
	} 
	//获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void
	jmethodID init_id=evn->GetMethodID(my_class,"<init>","(Ljava/lang/String;I)V");//(类,属性名.签名)	

	//创建Person对象--使用NewObject方法
	jobject person=evn->NewObject(my_class,init_id, result,20);

	//获取Person的Desc方法id
	jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");

	//调用创建的person里的desc方法
	evn->CallVoidMethod(person,desc_id);

}

 

运行结果:



 

 

 

  • 大小: 5.8 KB
  • 大小: 6.7 KB
  • 大小: 5.6 KB
4
0
分享到:
评论

相关推荐

    JNI创建java对象

    在本场景中,"JNI创建java对象"指的是利用JNI技术在C/C++原生代码中创建和操作Java对象。JNI在Android开发中尤其重要,因为Android系统的主要编程语言是Java,但为了实现高性能计算或调用操作系统底层功能,开发者...

    jni java传递对象到C

    6. **创建新的Java对象**:在C代码中创建Java对象,可以使用`NewObject`函数,传入类的`jclass`和构造函数的`jmethodID`。 7. **处理Java对象的引用**:在C代码中创建或修改了Java对象后,需要考虑其生命周期。使用...

    jni对象获取,使用jni从c++里获取Java对象

    JNI是Java平台标准的一部分,为开发者提供了在本地代码(如C或C++)中调用Java方法和字段,以及创建和操作Java对象的能力。JNI接口包括一组函数,这些函数允许本地代码与Java虚拟机(JVM)进行通信。 2. **注册...

    使用C++创建java虚拟机JVM,使用JNI调用java函数.zip

    本文将深入探讨如何使用C++创建Java虚拟机(JVM),并通过JNI来调用Java函数。这是一项技术性很强的任务,需要对C++编程、Java虚拟机的工作原理以及JNI接口有深入的理解。 首先,Java虚拟机(JVM)是Java平台的核心...

    Android调用Jni返回自定义对象

    这通常涉及到JNI的`NewObject`函数,用于创建Java对象。例如: ```cpp jobject createCustomObject(JNIEnv *env, int id, const char *name) { jclass customClass = env-&gt;FindClass(...

    JNI处理hashmap,string等对象的操作

    JNI接口提供了大量的函数,让本地方法(C/C++代码)能够创建、访问和修改Java对象。要使用JNI,你需要定义一个Java类,该类包含一个 native 方法声明,然后使用`javah`工具生成对应的C/C++头文件。接下来,编写实现...

    jni操作arraylist对象

    3. **创建int类型的Java对象**:由于ArrayList的`add`方法期望一个Object参数,我们需要将int值转换为Integer对象。为此,我们需要使用`env-&gt;NewObject`方法创建一个Integer对象。 ```c++ jclass integerClass = ...

    jni操作list集合,来存储对象

    Java对象在JNI中通常表示为`jobject`,而List集合则是一个特定类型的引用,可以通过`jclass`获取其类定义,并使用`NewObject`方法创建实例。对于存储自定义对象(如点对象Point)的情况,我们需要先定义一个JNI接口...

    JNI与Java方法的相互调用

    `JNIEnv *env`参数提供了访问Java对象和调用Java方法的接口,`jobject this`是Java对象的引用。 要调用Java方法,我们可以使用`env`指针提供的函数,比如`CallVoidMethod()`,它允许我们在本地代码中调用Java方法。...

    NDK编译 JAVA JNI 原生调用

    - `jclass`, `jobject`, `jmethodID`等类型:用于标识Java类、对象和方法ID,是JNI进行Java对象操作的关键。 5. JNI调用示例: 在Java中: ```java public class MyJNI { static { System.loadLibrary("myJNI...

    delphi通过JNI调用JAVA函数

    JNI接口提供了在本地代码中创建、访问和修改Java对象的方法,使得开发者可以将C/C++或者Delphi等本地代码嵌入到Java应用程序中。 要实现Delphi通过JNI调用Java函数,我们需要以下步骤: 1. **设置环境**:确保Java...

    jni返回对象数组例子

    本示例主要探讨如何在JNI中创建并返回一个对象数组到Java层。 首先,我们需要定义一个Java类,这个类将包含JNI方法的声明。例如,我们可能有一个`Person`类,表示一个人的信息: ```java public class Person { ...

    aes-jni-java和c互加解密

    Java对象在JNI层需要转换为本地指针,并在使用完毕后释放。同时,C/C++的原始字节数组也需要转换为Java的`byte[]`数组。 为了实现AES加密,C/C++代码通常会使用开源加密库,如OpenSSL或Bouncy Castle的C库。这些库...

    JNI中C调用Java方法的实例

    JNI提供了一套接口,让本地(native)代码能够访问Java虚拟机(JVM),执行Java类的方法,甚至创建和操作Java对象。这包括了加载类、找到方法ID、调用方法以及处理Java对象等操作。 在这个实例中,我们有以下几个...

    JNI-Java Native Interface资料(精华)

    通过JNI,开发人员可以创建、检查和更新Java对象(包括数组和字符串),调用Java方法,捕获和抛出异常,加载类并获取类信息,执行运行时类型检查。然而,使用JNI也意味着放弃了Java提供的某些好处,比如自动内存管理...

    jni 获得java窗口句柄的C语言源代码

    其中 `JNIEnv *env` 是 JNI 环境指针,`jobject window` 是 Java 层传来的窗口对象。 3. **初始化 JAWT 结构体:** - `JAWT awt;` 初始化 JAWT 结构体。 - `awt.version = JAWT_VERSION_1_3;` 设置版本号。 4. *...

    JNI_JAVA_C++.zip

    这涉及到创建Java对象,填充数组,或者直接返回基本类型。例如,你可以使用`NewObject`函数创建一个新的Java对象,然后使用`SetXXX`方法设置其属性。 3. **方法调用**:在C++中调用Java的方法,可以使用`...

    如何利用JNI实现Java插件开发

    JNI在Java与本地代码之间提供了一个桥梁,使得Java可以调用本地库中的函数,同时也允许本地代码实例化Java对象并调用其方法。 #### 二、背景与目标 本文的主要目标是通过JNI技术来实现在Java应用程序中调用已有的...

    jni.zip_C++ JNI_JNI 调用java_c调用java_jni_jni jdk1

    这包括获取类的ID,创建Java对象,以及调用Java方法。 5. **数据类型转换**: JNI提供了Java和本地类型之间的转换。例如,将Java的`int`转换为C++的`jint`,将Java对象转换为`jobject`等。 6. **异常处理**: ...

    JNI实例 Java调用DLL c++调用Java

    1. 创建Java类,并在其中声明需要被C++调用的方法,同样标记为native。 2. 使用javah生成对应的头文件。 3. 在C++代码中,使用JNIEnv指针来访问Java对象和方法。JNIEnv提供了多种方法,如FindClass找到Java类,...

Global site tag (gtag.js) - Google Analytics