zoukankan      html  css  js  c++  java
  • JNI 方法注册与签名+BufferedReader使用readLine问题

    最近了解了关于Java JNI接口的一些关于方法注册与签名相关的知识,在此进行一下总结。

    使用JNI接口时,我们首先需要把Java方法声明为native:

    [java] view plain copy
     
    1. public native void f();  


    然后编写对应的C/C++代码,并编译成为动态链接库(.dll或.so),在调用Java方法前载入动态链接库即可调用:

    [java] view plain copy
     
    1. static {  
    2.     System.loadLibrary("native-lib");  
    3. }  


    那么,Java文件中的native方法是如何与native文件中的方法一一对应的呢?

    在此有两种方法:静态注册与动态注册,下面将一一介绍:

    静态注册

    采用静态注册时,Java层的native方法与native层的方法在名称上具有一一对应的关系,具体要求如下:
    native层的方法名为:Java_<包名>_<类名>_<方法名>(__<参数>)
    其中,包名使用下划线代替点号进行分割
    只有当native方法出现需要重载的时候,native层的方法名后才需要跟上参数(括号里的内容),参数的编写形式与JNI签名相关(后面会介绍)
    通常而言,我们可以把native方法集中在一个类中,然后调用:
    [plain] view plain copy
     
    1. javah -jni 包名.类名  

    自动生成对应的c层头文件
    下面是静态注册的例子:
    Java层:
    [java] view plain copy
     
    1. package com.app.superxlcr.jnitest;  
    2.   
    3. /** 
    4.  * Created by superxlcr on 2017/5/25. 
    5.  */  
    6.   
    7. public class NativeTest {  
    8.   
    9.     public native void f();  
    10.   
    11.     public native int f(int a, double b);  
    12.   
    13.     public native void f(Object a, String b);  
    14.   
    15.     public native void g();  
    16.   
    17. }  

    native层:
    [cpp] view plain copy
     
    1. /* DO NOT EDIT THIS FILE - it is machine generated */  
    2. #include <jni.h>  
    3. /* Header for class com_app_superxlcr_jnitest_NativeTest */  
    4.   
    5. #ifndef _Included_com_app_superxlcr_jnitest_NativeTest  
    6. #define _Included_com_app_superxlcr_jnitest_NativeTest  
    7. #ifdef __cplusplus  
    8. extern "C" {  
    9. #endif  
    10. /* 
    11.  * Class:     com_app_superxlcr_jnitest_NativeTest 
    12.  * Method:    f 
    13.  * Signature: ()V 
    14.  */  
    15. JNIEXPORT void JNICALL Java_com_app_superxlcr_jnitest_NativeTest_f__  
    16.   (JNIEnv *, jobject);  
    17.   
    18. /* 
    19.  * Class:     com_app_superxlcr_jnitest_NativeTest 
    20.  * Method:    f 
    21.  * Signature: (ID)I 
    22.  */  
    23. JNIEXPORT jint JNICALL Java_com_app_superxlcr_jnitest_NativeTest_f__ID  
    24.   (JNIEnv *, jobject, jint, jdouble);  
    25.   
    26. /* 
    27.  * Class:     com_app_superxlcr_jnitest_NativeTest 
    28.  * Method:    f 
    29.  * Signature: (Ljava/lang/Object;Ljava/lang/String;)V 
    30.  */  
    31. JNIEXPORT void JNICALL Java_com_app_superxlcr_jnitest_NativeTest_f__Ljava_lang_Object_2Ljava_lang_String_2  
    32.   (JNIEnv *, jobject, jobject, jstring);  
    33.   
    34. /* 
    35.  * Class:     com_app_superxlcr_jnitest_NativeTest 
    36.  * Method:    g 
    37.  * Signature: ()V 
    38.  */  
    39. JNIEXPORT void JNICALL Java_com_app_superxlcr_jnitest_NativeTest_g  
    40.   (JNIEnv *, jobject);  
    41.   
    42. #ifdef __cplusplus  
    43. }  
    44. #endif  
    45. #endif  

    我们可以看到,对于拥有重载的f 方法,其native方法名称后都带有参数,而没有重载的g 方法则没带有
    静态注册JNI方法的弊端非常明显,就是方法名会变得很长,因此下面我们介绍另外一种动态注册的方法
     

    动态注册

    使用动态注册时,我们需要准备好需要自己想要对应的native方法,然后构造JNINativeMethod数组,JNINativeMethod是一种结构体,源码如下:
    [cpp] view plain copy
     
    1. typedef struct {  
    2.     // Java层native方法名称  
    3.     const char* name;  
    4.     // 方法签名  
    5.     const char* signature;  
    6.     // native层方法指针  
    7.     void*       fnPtr;  
    8. } JNINativeMethod;  

    然后重写JNI_OnLoad方法(该方法会在Java层通过System.loadLibrary加载完动态链接库后被调用),我们在其中进行动态注册工作:
    [cpp] view plain copy
     
    1. JNIEXPORT jint JNICALL  
    2. JNI_OnLoad(JavaVM* vm, void* reserved) {  
    3.     JNIEnv *env = NULL;  
    4.     jint result = -1;  
    5.   
    6.     // 获取JNI env变量  
    7.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
    8.         // 失败返回-1  
    9.         return result;  
    10.     }  
    11.   
    12.     // 获取native方法所在类  
    13.     const char* className = "com/app/superxlcr/jnitest/MainActivity";  
    14.     jclass clazz = env->FindClass(className);  
    15.     if (clazz == NULL) {  
    16.         return result;  
    17.     }  
    18.   
    19.     // 动态注册native方法  
    20.     if (env->RegisterNatives(clazz, methods, 1) < 0) {  
    21.         return result;  
    22.     }  
    23.   
    24.     // 返回成功  
    25.     result = JNI_VERSION_1_4;  
    26.     return result;  
    27. }  

    动态注册的大致步骤如下:
    1. 通过vm(Java虚拟机)参数获取JNIEnv变量
    2. 通过FindClass方法找到对应的Java类
    3. 通过RegisterNatives方法,传入JNINativeMethod数组,注册native函数
    对于JNINativeMethod结构而言,签名是其非常重要的一项元素,它用于区分Java中native方法的各种重载形式,下面将介绍方法的签名
     

    方法签名

    方法签名对于区分Java层native重载方法有重大意义
    总的来说,方法签名的组成规则为:
    [plain] view plain copy
     
    1. (参数类型标识1参数类型标识2...参数类型标识n)返回值类型标识  
     
    类型标识对应关系如下:
    类型标识 Java类型
    Z boolean
    B byte
    C char
    S short
    I int
    J long
    F float
    D double
    L包名/类名; 各种引用类型
    V void

    另外,当Java类型为数组时,在标识前会有“[”符号,例如:String[] 类型标识为 [Ljava/lang/String;
     
    下面举几个例子:
    [java] view plain copy
     
    1. // Signature: ()V  
    2. public native void f();  
    3.   
    4. // Signature: (ID)I  
    5. public native int f(int a, double b);  
    6.   
    7. // Signature: (Ljava/lang/Object;Ljava/lang/String;)V  
    8. public native void f(Object a, String b);  
    9.   
    10. // Signature: ()V  
    11. public native void g();  
        1. BufferedReader使用readLine问题
        2. 有时我们在使用BufferedReader时候会发现使用readLine函数迟迟没有任何返回,这是因为BufferedReader和BufferedWriter是基于行进行操作的,因此我们使用BufferedWriter的时候使用newLine函数即可,具体代码如下:

          [java] view plain copy
           
          1. BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));  
          2. writer.write(str);  
          3. writer.newLine();  
          4. writer.flush();  
          5.   
          6. BufferedReader reader = new BufferedReader(new InputStreamReader(in));  
          7. str = reader.readLine();  
  • 相关阅读:
    导入贴图操作:处理贴图MaxSize和Format
    修改贴图工具
    CharacterMotor_刚体角色驱动
    sine曲线向前运动
    Shader基础(固定管线着色器)
    Shader基础(渲染管线)
    Unity3D中的高级摄像机跟随
    蛋疼的 qii 神马警告才是需要注意的警告?(由于警告引起的截然不同的运行结果)
    模拟摄像头,AV视频信号线解码,PAL制 NTSC,输入解码显示,终于搞定,记录下!
    VIP 视频开发板 上位机 测试软件 下载地址,玩转各自分辨率(V201抢先版)
  • 原文地址:https://www.cnblogs.com/KingIceMou/p/6976557.html
Copyright © 2011-2022 走看看