Java与C连动时的数据类型分析

来源:http://blog.csdn.net/flxyzsby/article/details/597588




. JavaC连动时的数据类型分析
        刚才我们只是举了一个简单的例子来说明连动的基本方法
我们在编写真正实用的程序的时候 , 我们必然需要传递参数 .Java  C 数据类型的对应关系是这样的
 
-----------------------------------------------------------------------------------------------------------------------
Java 数据类型                      C 数据类型                     字节数
-----------------------------------------------------------------------------------------------------------------------
boolean                        jboolean                       1
byte                      jbyte                            1
char                            jchar                           2
short                           jshort                          2
int                        jint                       4
long                      jlong                            8
float                      jfloat                            4
double                          jdouble                         8
-----------------------------------------------------------------------------------------------------------------------
 
Java 所有的数组都拥有相应的 C 数组类型
 
-----------------------------------------------------------------------------------------------------------------------
Java 数据类型                      C 数据类型                          
-----------------------------------------------------------------------------------------------------------------------
Boolean[]                                      jbooleanArray                               
byte[]                                     jbyteArray                                     
char[]                                    jcharArray                                    
short[]                                   jshortArray                                   
int[]                              jintArray                                       
long[]                                     jlongArray                                     
float[]                                    jfloatArray                                    
double[]                                 jdoubleArray                                 
object[]                                  jobjectArra y                         
-----------------------------------------------------------------------------------------------------------------------
还有一个类型 jarray, 它是一个通用数组
jini.h 可以看出
C , 所以的数组数据类型都是 jobject 的同义类型 , 但是在 C++ 中是有继承关系的 .
继承关系为
Jobject <  ――  jarray <  ―― jobjectArra y,  jbooleanArray, jbyteArray, jcharArray, jshortArray, jintArray, jlongArray, jfloatArray, jdoubleArray
 
对这些数组类型的操作函数典型的有
jsize (JNICALL *GetArrayLength)
      (JNIEnv *env, jarray array);
获得数组的长度 , 适用于所有类型
你可以这样使用
C
jsize length = (*env)->GetArrayLength(env,array);
C++
Jsize length = env->GetArrayLength(array);
C C++ 中使用略有区别 , 请大家使用注意以下 , 下面提到的函数也是如此 .
 
 
在标题文件 jni.h , 这些数据类型用 typedef 语句声明为目标平台上的等价数据类型 .
还有这两个常量  JNI_FALSE = 0 JNI_TRUE = 1.
 
jboolean * (JNICALL *GetBooleanArrayElements)
      (JNIEnv *env, jbooleanArray array, jboolean *isCopy);
    jbyte * (JNICALL *GetByteArrayElements)
      (JNIEnv *env, jbyteArray array, jboolean *isCopy);
    jchar * (JNICALL *GetCharArrayElements)
      (JNIEnv *env, jcharArray array, jboolean *isCopy);
    jshort * (JNICALL *GetShortArrayElements)
      (JNIEnv *env, jshortArray array, jboolean *isCopy);
    jint * (JNICALL *GetIntArrayElements)
      (JNIEnv *env, jintArray array, jboolean *isCopy);
    jlong * (JNICALL *GetLongArrayElements)
      (JNIEnv *env, jlongArray array, jboolean *isCopy);
    jfloat * (JNICALL *GetFloatArrayElements)
      (JNIEnv *env, jfloatArray array, jboolean *isCopy);
    jdouble * (JNICALL *GetDoubleArrayElements)
      (JNIEnv *env, jdoubleArray array, jboolean *isCopy);
这些函数获得数组的内容 , 返回数组指针 , i sCopy  如果进行拷贝,指向以 JNI_TRUE 填充的 jboolean, 否则指向以 JNI_FALSE 填充的 jboolean
 
    void (JNICALL *ReleaseBooleanArrayElements)
      (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
    void (JNICALL *ReleaseByteArrayElements)
      (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
    void (JNICALL *ReleaseCharArrayElements)
      (JNIEnv *env, jcharArray array, jchar *elems, jint mode);
    void (JNICALL *ReleaseShortArrayElements)
      (JNIEnv *env, jshortArray array, jshort *elems, jint mode);
    void (JNICALL *ReleaseIntArrayElements)
      (JNIEnv *env, jintArray array, jint *elems, jint mode);
    void (JNICALL *ReleaseLongArrayElements)
      (JNIEnv *env, jlongArray array, jlong *elems, jint mode);
    void (JNICALL *ReleaseFloatArrayElements)
      (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
    void (JNICALL *ReleaseDoubleArrayElements)
      (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);
这些函数用于通知虚拟机指针已经不再需要 .
其中 mode  的参数有
0 =在更新数组元素后释放 elems 缓冲器
JNI_COMMIT =在更新数组元素后不释放 elems 缓冲器
JNI_ABORT =不更新数组元素释放 elems 缓冲器
 
 void (JNICALL *GetBooleanArrayRegion)
      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
    void (JNICALL *GetByteArrayRegion)
      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
    void (JNICALL *GetCharArrayRegion)
      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
    void (JNICALL *GetShortArrayRegion)
      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
    void (JNICALL *GetIntArrayRegion)
      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
    void (JNICALL *GetLongArrayRegion)
      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
    void (JNICALL *GetFloatArrayRegion)
      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
    void (JNICALL *GetDoubleArrayRegion)
      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
 
    void (JNICALL *SetBooleanArrayRegion)
      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf);
    void (JNICALL *SetByteArrayRegion)
      (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf);
    void (JNICALL *SetCharArrayRegion)
      (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf);
    void (JNICALL *SetShortArrayRegion)
      (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf);
    void (JNICALL *SetIntArrayRegion)
      (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
    void (JNICALL *SetLongArrayRegion)
      (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf);
    void (JNICALL *SetFloatArrayRegion)
      (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf);
    void (JNICALL *SetDoubleArrayRegion)
      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf);
这些函数用于访问和设置局部元素 .
其他函数请参照 jni.h
 
. JavaC连动参数的传递
还有我要和你讨论的是参数传递有值传递和地址 ( 还有引用传递 ) 传递的两种方式 . 在它们连动时我们也要进行这两种传递的实现 .
 
我们知道 Java 参数传递都是值传递 , 而没有地址传递的说法 . 但是为了带回参数的变化值 ( 你不可能把所有的信息都在函数返回值里返回 ), 我们不得不创造一个等价的地址传递方式 .
幸运的是 Java 里的对象是可以作为参数传递给函数并且可以带回其在函数中的变化 ( 从内部实现机制看 , 其实就是一种引用传递 ).
于是我们的出结论 :
Java 中传递用传递值静态对象时为值传递 , new 传递对象引用传递 .
 
我们要编写这样的一个函数 : 将一个 byte[] 里的内容拷贝到另一个 byte[] 
int javabytecpy( byte[] dest,  byte [] src,  int req_byte_len);
我们的 java 文件内容为
package java2c.testdll;
import java.io.UnsupportedEncodingException;
public class javatest {
         public static void main(String args[]){
        
                   int rtn = 0;
                   String str=" 你好我的祖国 --China";
                   byte[] src_byte_array = str.getBytes();
                   byte[] dest_byte_array =new byte[src_byte_array.length];
                   System.out.println(" 拷贝前源 byte 数组内容为 : " +BytearrayToStgring(src_byte_array));
                   System.out.println(" 拷贝后目标 byte 数组内容为 :"+BytearrayToStgring(dest_byte_array));
                   System.out.println("DLL  函数返回值为 "+rtn);
                   rtn = javabytecpy(dest_byte_array, src_byte_array, 6);
                   System.out.println(" 拷贝前源 byte 数组内容为 : " +BytearrayToStgring(src_byte_array));
                   System.out.println(" 拷贝后目标 byte 数组内容为 :"+BytearrayToStgring(dest_byte_array));
                  
                   System.out.println("DLL  函数返回值为 "+rtn);
         }
         //  加载库
         static {
                   //  显示 java.library.path 内容
                   System.out.println(System.getProperty("java.library.path"));
                   //  在这里加载的是 C/C++ 生成的 DLL 文件名 , 这里是 java_c_dll.dll
                   System.loadLibrary("java_c_dll");
                   System.out.println("------------------DLL Started--------------------------");
         }
         /**
         * 参数 :
         *dest  目标数组                                 对象传递
         *src  源数组                                     对象传递
         *dest_byte_len  需要拷贝长度    值传递
         * 返回值 :
         * 成功  0 , 失败  -1
         **/
         public native static int javabytecpy( byte[] dest, byte [] src, int req_byte_len);
        
    public static String BytearrayToStgring(byte[] byte_in){
        try{
            String encoding="GB2312";
            String ret_str=new String(byte_in,encoding);
            return ret_str;
        }
        catch(UnsupportedEncodingException exp){
             return "";
        }
    }
 
} 生成的头文件为
java2c_testdll_javatest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class java2c_testdll_javatest */
 
#ifndef _Included_java2c_testdll_javatest
#define _Included_java2c_testdll_javatest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     java2c_testdll_javatest
 * Method:    javabytecpy
 * Signature: ([B[BI)I
 */
JNIEXPORT jint JNICALL Java_java2c_testdll_javatest_javabytecpy
 (JNIEnv *, jclass, jbyteArray, jbyteArray, jint);
 
#ifdef __cplusplus
}
#endif
#endif
我们的 C/C++ 实现文件为
java2c_testdll_javatest.cpp
#include "stdio.h"
#include "jni_md.h"
#include "java2c_testdll_javatest.h"
/*
 * Class:     java2c_testdll_javatest
 * Method:    execute
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_java2c_testdll_javatest_javabytecpy
          (    JNIEnv *   env,
               jclass     cls,
               jbyteArray dest_byte_array,
               jbyteArray src_byte_array,
               jint       req_len){
               printf("DLL 调用开始 ./n");
               if ( env->GetArrayLength(src_byte_array) < req_len ){
                    printf(" 你需要的长度超过源 byte 数组 ./n");
                    return -1;
               };
               if ( env->GetArrayLength(dest_byte_array) < env->GetArrayLength(src_byte_array)){
                    printf(" 你的目标数组小于源数组 ./n");
                    return -1;
               };
               jbyte* byte_temp = env->GetByteArrayElements(src_byte_array, JNI_FALSE);
               env->SetByteArrayRegion(dest_byte_array, 0, req_len, (const jbyte*)byte_temp);
               printf("DLL 调用结束 ./n");
          return 0;
};
 
我们运行的结果是
C:/WINNT/system32;.;C:/WINNT/system32;C:/WINNT;C:/WINNT/system32;C:/WINNT;C:/WINNT/System32/Wbem;D:/Program Files/Microsoft Visual Studio/Common/Tools/WinNT;D:/Program Files/Microsoft Visual Studio/Common/MSDev98/Bin;D:/Program Files/Microsoft Visual Studio/Common/Tools;D:/Program Files/Microsoft Visual Studio/VC98/bin;D:/Java/jdk1.5.0_02/bin
------------------DLL Started--------------------------
拷贝前源 byte 数组内容为 你好我的祖国 --China
拷贝前目标 byte 数组内容为 :                  
DLL  函数返回值为 0
拷贝后源 byte 数组内容为 你好我的祖国 --China
拷贝后目标 byte 数组内容为 : 你好我             
DLL  函数返回值为 0
DLL 调用开始 .
DLL 调用结束 .
 
这个例子中我们看到了函数传递参数的方法 . 限于篇幅,我们也不深入讨论了 .
C/C++ 端的编程大家可以参照 jni.h 里的各种声明 , 我想熟悉 C/C++ 的都可以看的明白 . 并很快熟练地掌握 . 你必须保证你的 C/C++ 程序正确而且没有内存泄露,否则你的虚拟机将会捕捉到无法处理的异常而退出或者崩溃 . 你可能会花费很多时间才能找到错误 . 所以我们的程序必须经过严格的测试才能应用 .
还有一点提醒大家,与 C/C++ 函数传递参数的时候请你对字符的转换一下, 因为 java 字符 unicode 编码的 , C/C++ 中有选择的 , 普通的是 ascii , 你在实际开发过程中 , 请参照相关的 Java unicode 解码编码的资料 .
 
 
 
 
附录一
javah
功能说明:
头文件和  Stub  文件生成器。 javah   Java  类生成  C  头文件和  C  源文件。这些文
件提供了连接胶合,使  Java   C  代码可进行交互。
语法:
javah [  命令选项  ] fully-qualified-classname. . .
javah_g [  命令选项  ] fully-qualified-classname. . .
补充说明:
javah  生成实现本地方法所需的  C  头文件和源文件。 程序用生成的头文件和源文件在
本地源代码中引用某一对象的实例变量。 .h  文件含有一个  struct  定义,该定义的布局
与相应类的布局平行。该  struct  中的域对应于类中的实例变量。
头文件名以及在头文件中所声明的结构名都来源于类名。如果传给  javah  的类是在某个
包中,则头文件名和结构名前都要冠以该包名。下划线  (_)  用作名称分隔符。
缺省情况下, javah  为每个在命令行中列出的类都创建一个头文件,且将该文件放在当
前目录中。用  -stubs  选项创建源文件。用  -o  选项将所有列出类的结果串接成一个单
一文件。
缺省情况下, javah  为每个在命令行中列出的类都创建一个头文件,且将该文件放在当
前目录中。用  -stubs  选项创建源文件。用  -o  选项将所有列出类的结果串接成一个单
一文件。
命令选项
-o[ 输出文件 将命令行中列出的所有类的头文件或源文件串接到输出文件中。 -o   -
两个选项只能选择一个。
-d[ 目录 设置  javah  保存头文件或  stub  文件的目录。 -d   -o  两个选项只能选择一
个。
-stubs  使  javah   Java  对象文件生成  C  声明。
-verbose  指明长格式输出,并使  javah  将所生成文件的有关状态的信息输出到标准输
出设备中。
-help  输出  javah  用法的帮助信息。
-version  输出  javah  的版本信息。
-jni  使  javah  创建一输出文件,该文件包含  JNI  风格的本地方法函数原型。这是缺省
输出,所以  -jni  的使用是可选的。
-classpath[ 路径 指定  javah  用来查询类的路径。如果设置了该选项,它将覆盖缺省
值或  CLASSPATH  环境变量。目录用冒号分隔。
-bootclasspath[ 路径 指定加载自举类所用的路径。缺省情况下,自举类是实现核心
Java  平台的类,位于  jrelib
t.jar   jrelibi18n.jar  中。
-old  指定应当生成旧  JDK1.0  风格的头文件。
-force  指定始终写输出文件 .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
水资源是人类社会的宝贵财富,在生活、工农业生产中是不可缺少的。随着世界人口的增长及工农业生产的发展,需水量也在日益增长,水已经变得比以往任何候都要珍贵。但是,由于人类的生产和生活,导致水体的污染,水质恶化,使有限的水资源更加紧张。长期以来,油类物质(石油类物质和动植物油)一直是水和土壤中的重要污染源。它不仅对人的身体健康带来极大危害,而且使水质恶化,严重破坏水体生态平衡。因此各国都加强了油类物质对水体和土壤的污染的治理。对于水中油含量的检测,我国处于落后阶段,与国际先进水平存在差距,所以难以满足当今技术水平的要求。为了取得具有代表性的正确数据,使分析数据具有与现代测试技术水平相应的准确性和先进性,不断提高分析成果的可比性和应用效果,检测的方法和仪器是非常重要的。只有保证了这两方面才能保证快速和准确地测量出水中油类污染物含量,以达到保护和治理水污染的目的。开展水中油污染检测方法、技术和检测设备的研究,是提高水污染检测的一条重要措施。通过本课题的研究,探索出一套适合我国国情的水质污染现场检测技术和检测设备,具有广泛的应用前景和科学研究价值。 本课题针对我国水体的油污染,探索一套检测油污染的可行方案和方法,利用非分散红外光度法技术,开发研制具有自主知识产权的适合国情的适于野外便携式的测油仪。利用此仪器,可以检测出被测水样中亚甲基、甲基物质和动植物油脂的污染物含量,为我国众多的环境检测站点监测水体的油污染状况提供依据。
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值