java学习之JNI 学习四 创建JAVA对象

在c/c++本地代码中创建Java对象

      1,使用函数NewObject可以用来创建JAVA对象;

 

         GetMethodID 能够取得构造方法的jmethodID, 如果传入的要取得的方法名称设为"<init>"就能够取得构造方法

         构造方法的方法返回值类型的签名始终为void

         例:

         jclass clazz_date = env->FindClass("java/util/Date");

 

         jmethodID mid_date = env->GetMethoID(clazz_date, "<init>", "()V");

 

         jobject now = env->NewObject(clazz_date, mid_date);

 

          jmethodID mid _date_getTime = env->GetMethodID(clazz_date, "getTime" , "()")

          jlong  time =    env->CallLongMethod(now, mid_date_getTime);

 

     2,使用函数AllocObject来创建JAVA对象

          使用函数AllocObject可以根据传入的jclass创建一个JAVA对象,便是他的状态是非初始化的,在使用这个对象之前绝对要用CallNovirtualVoidMethod来调用该jclass的建构函数,这样可以延迟构造函数的调用,这一个部分用的很少,在这里只做简单的说明。

  

          jclass clazz_str = env->FindClass("java/lang/String");

          jmethodID methodID_str = env->GetMethodID(clazz_str ,"<init>", "([C)V");

      

          //预先创建一个没有初始化的字符串

 

         jobject string = env->AllocObject(clazz_str);

       

        //创建一个4个元素的的字符数组,然后以“清”,“原”,“卓”,“也”赋值

  

       jcharArra  arg = env->NewCharArray(4);

 

       env->SetCharArrayRegion(arg, 0, 4,L"清原卓也");

     

       // 呼叫构建子

 

      env->CallNovirtualVoidMethod(string ,clazz_str,methodID,arg);

        

      jclass clazz_this = env->GetObjectClass(obj);

 

     //这里假设这个对象的类有定义

 

   static string  STATIC_STR;

   jfieldID fieldID_str = env->GetStaticFieldID(clazz_this,"STATIC_STR","Ljava/lang/String");

   env->SetStaticObjectField(clazz_str, fieldID_str, string);

 

 

  •    JAVA字串 <----->c/c++的字串

      在JAVA中,使用的字符串String对象是Unicode(UTF-16)码,即每个字符不论是中文还是英文还是符号,一个字符总是占两个字节

      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*)跟UTF8编码的字符串(char*)

        cost jchar* GetStringChars(jstring str, jboolean* copied)

       cost char* GetStringUTFChars(jstring str, jboolean *copied)

       第一个参数传入一个指向JAVA的String对象的jstring变量

       第二个参数传入的是一个jboolean的指针

      

       这两个函数分别都会有两个不同的动作:

       1,开辟新的内存,然后把JAVA中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。

       2,直接返回指向JAVA的String的内存的指针,这个时候千万不要改变这个内存的内容,这将破坏String在Java中始终是常量这个原则

       第二个参数是用来标示是否对Java的String对象进行了拷贝的。

       如果传入的这个jboolean指针不是NULL,则他会给该指针所指向的内存传入JNI_TRUE 或 JNI _FALSE标示是否进行了拷贝。      

       传入NULL表示不关心是否拷贝字符串,它就不会给jboolean*指向的内存赋值

      

       使用这两个函数取得的字符串,在不使用的时候,要使用ReleaseStringChars/ReleaseStringUTFChars来释放拷贝的内存,或是释放对JAVA的String对象的引用。

        ReleaseStringChars(jstring jstr, const jchar* str)

        ReleaseStringUTFChars(jstring jstr, const char* str)

 第一个参数指定一个jstring 变量,即是要释放的本地字符串的来源

 第二个参数就是要释放的本地字符串

 

    GetStringCritical

   

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

 

   const jchar* GetStringCritical(jstring str, jboolean* copied);

   void ReleaseStringCritical(jstring jstr, const jchar* str);

  

   在GetStringCritical/ReleaseStringCritical之间是一个关键区,在这关键区之中绝对不能呼叫JNI的其它函数和会造成当前线程中断或是会让当前线程等待的任何本地代码,否则将造成关键区代码执行期间垃圾回收器停止动作,任何触发垃圾回收器的线程也会暂停,其他的触发垃圾回收器的线程不能前进直到当前线程结束而激活垃圾回收器

  

    在关键区千万不要出现中断操作,或是在JVM中分配任何新对象,否则会造成JVM死锁。  

 

    虽说这个函数会增加直接传回指向JAVA字符串的指针的可能性,不过还是会根据情况传回拷贝过的字符串

 

 

    不支持GetStringUTFCritical,没有这样的函数,因为JAVA字符串用的是UTF-16,要转换成UTF-8编码的字符串始终需要进行一次拷贝,所以没有这样的函数

 

   GetStringRegion

   GetStringUTFRegion

  

   JAVA1.2F出来的函数,这个函数的动作,是把JAVA字符串的内容直接拷贝到C/C++的字符数组中,在呼叫这个函数之前必须有一个C/C++分配出来的字符串,然后传入到这个函数中进行字符串的拷贝。

   由于C/C++分配内存开销相对小,而且JAVA中的String内容拷贝的开销可以忽略,更好的一点是些函数不会分配内存,不会抛出OutOfMemoryError异常

  //拷贝JAVA字符串并以UTF-8编码传入buffer

  GetStringUTFRegion(jstring str , jsize start, jsize len, char* buffer);

 

  //拷贝JAVA字符串并以UTF-16编码传入buffer

  GetStringRegion(jstring str , jsize start, jsize len, char* buffer);

 

 

 

  其他的字符串函数

 

  jstring NewString(const jchar* str , jsize len);

  jstring NewStringUTF(const char* str);

  jsize GetStringLength(jstring  str);

  jsize GetStringUTFLength(jstring str)

 

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JNI创建 Java 接口对象需要经过以下几个步骤: 1. 获取对应 Java 类的 jclass 对象。 2. 获取对应 Java 类的构造函数的 jmethodID 对象。 3. 调用构造函数创建 Java 对象。 4. 将创建Java 对象转换成对应的 jobject 对象。 下面是一个具体的示例代码,假设需要创建以下的 Java 接口对象: ```java public interface MyInterface { void myMethod(); } ``` 在 JNI 层中创建这个接口对象的具体代码如下: ```c++ // 获取 MyInterface 类的 jclass 对象 jclass clazz = env->FindClass("com/example/MyInterface"); // 获取 MyInterface 构造函数的 jmethodID 对象 jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); // 调用 MyInterface 的构造函数创建 Java 对象 jobject myInterfaceObj = env->NewObject(clazz, constructor); // 将 Java 对象转换成 jobject 对象 jobject myInterface = env->NewGlobalRef(myInterfaceObj); // 释放局部引用 env->DeleteLocalRef(myInterfaceObj); ``` 在这个示例代码中,首先通过 `FindClass()` 函数获取 `MyInterface` 类的 jclass 对象;然后通过 `GetMethodID()` 函数获取 `MyInterface` 类的构造函数的 jmethodID 对象;接着调用 `NewObject()` 函数创建 `MyInterface` 的 Java 对象;最后通过 `NewGlobalRef()` 函数将 Java 对象转换成 jobject 对象,并将其存储在 `myInterface` 变量中。需要注意的是,在调用 `NewGlobalRef()` 函数之后,需要释放局部引用,否则将会导致内存泄漏。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值