Java与C/C++的连动

Java C/C++ 的连动
--- Java C/C++ 的方法 的相互调用     
----------- 徐兆元              
 
前言 关于我的 JAVA
. Java C 的接口
. Java C 连动的实现
. Java C 连动时的数据类型分析及 C 端函数处理
. Java C 连动参数的传递
. 关于异常( *
.C 调用 Java(*)
(由于最近工作太忙 ,* 号的标题的内容我会在这个至急得项目完成之后再写出来与大家分享)
 
关于我的 JAVA
各种关于 Java 强大的功能以及美好的前途的说法我已经听了太多太多.而我还是一直在开发着各种平台 C/C++ 程序.对 Java 的向往已久 , 在大学里开发的 Java 程序只能叫鸡毛蒜皮.如今,我终于有机会开发实用的 Java 程序.这让我真正感受了 Java
       天哪!在开发的实际过程中,我经常感叹!我心爱的指针没有了,也没有显式的引用,没有默认参数(你只能重载,不过 JDK1.5 已经支持) . 更可恨的是为了带回一个需要利用的值 , 你必须去 new 一个对象 , 而这个对象必须经过你的转换才是你需要的值,而这个别人在阅读你的代码的时候很难看出来 . 或许我的实现是一个 C/C++ 风格的,所以看起来比较撇足 . 但是我真的找不到那种灵活的实现方法 , 一切都需要那么多资源 , 真是让我心疼 .
       发了这么多的牢骚 , 只能说明我不是一个 Java 高手 . 我知道它与 C++ 有很大的区别(有的人将 Java 称为 C++-- . 不过它的简单易学及强大的安全性(这里指的是程序不易崩溃性,不是网络的安全)真的令我们着迷 .
 
 
在你阅读这篇文章的时候,如果你真正打算写这样的程序 . 那么请你准备下列的条件 .
操作系统 :Windows/Unix/Linux/Solaris 中的一个
JAVA 环境 : 建议 JDK1.4 以上的版本
C/C++ 环境 : C/C++ 编译器 .
 
为什么我要进行连个语言的联动 .?
你知道 C/C++ 的优点 , 你需要利用它的高效写出符合你程序要求的代码,而这个 Java 无法实现,或者你拥有了一个处理的 C/C++ 代码 , 而你如果用 Java 来重写将付出巨大的代价 . 那么你凭什么不重用这些代码呢?原因等等 .
 
. Java C 的接口 Jini
       JDK 中,你会发现有这个目录 :%JAVA_HOME%include, 里面包含了这些文件
%JAVA_HOME% include
 jawt.h
 jni.h
 jvmdi.h
 jvmpi.h
└─ win32
        jawt_md.h
        jni_md.h
很明显这些是为了 C/C++ 准备的 .
其中
jni.h: 定义与 C/C++ 接口函数
jni_md.h: 定义基本数据类型接口
include/jawt.h include/win32/jawt_md.h: 提供标准化方法访问本地绘图功能开发 .
jvmdi.h jvmpi.h:: 提供 Java 虚拟机与外部的接口 .
lib 文件夹下 , 有它们的库文件 .
 
. Java C 连动的实现
在认识了这些接口文件之后 , 我们来明确一下开发 Java C/C++ 联动的基本步骤 :
      Java 中声明需要调用的 C 函数名称,即为函数生成一个 C/C++ 存根,以便在 Java 平台与实际的 C 函数之间进行转换 . 其实就是利用 Java 生成一个 C/C++ 的头文件 . 当它们在进行连接时 , 虚拟机将从栈中提取信息 ,
      利用前一步生成的存根即头文件在 C/C++ 环境中生成共享库文件 .
      使用 Java 的专用方法 System.loadLibrary 将第二个步骤生成的共享库加载进来 .
剩下的就是你在他们之间不断地调试了 , 直到程序满足你的要求 .
 
下面我们来具体分析每一个步骤并举例 .( 这一处为了说明方法 , 我们先写简单的例子 )
假设我们的需求是这样的 :
  Java 调用 C 中的打印信息函数 , 并且返回是否成功的操作 .
      Java 中头文件的生成
javah 工具用来为 Java 类的本地函数生成 C/C++ 头文件, javac 工具用来编译 Java 源文件。
 
我们写这样一个类
package java2c.testdll;
public class javatest {
public static void main(String args[]){
int rtn = execute();
System.out.println("DLL 函数返回值为 "+rtn);
}
// 加载库
static {
System.out.println(System.getProperty("java.library.path"));
System.loadLibrary("java_c_dll");
// 在这里加载的是 C/C++ 生成的 DLL 文件名 , 这里是 java_c_dll.dll
System.out.println("------------------DLL Started--------------------------");
}
public native static int execute();
}
这是一个简单的不能的例子了 , 但它已经能说明核心了 .
System.loadLibrary 可以加载库 , 这里不用写出后缀 , 系统会自动检测它是 dll 格式还是 SO 等格式 .
public native static int execute()就是我们声明要在C中实现的函数
这里将起声明为本地方法.
 
接着我们应该根据这个类写一个 C/C++ 的头文件 , 它的书写规则是这样的 :
(1) 使用完整的 Java 方法名 . HelloBaby.sayHello, 如果类在一个包里 , 那么应该在 Java 方法的名称前加包名称 . com.interface.dll.common.HelloBaby.sayHello.
(2) 用下划线取代圆点 , 在加上前缀 Java_. Java_com_interface _dll_common_HelloBaby_sayHello.
 
(3) 如果类名中的字符包含不是 ASCII 码或者数字的字符 , ’_’,’$’ 或者 Unicode 字符 , 那么用 _0xxxx 代替他们 , 其中 xxxx 是该字符的 Unicode 值的 4 个十六进制数字序列 .
: 如果你有重载方法 , 那么你需要在后面加上双下划线 . 比如你有一个 sayHello 的重载 . 那么第一个叫 Java_com_interface _dll_common_HelloBaby_sayHello._ _ 第二个则叫 Java_com_interface _dll_common_HelloBaby_sayHello._ _I
 
其实我们是没有必要去手动建立这个头文件的的 . 因为我们有 javah 实用程序
它是使用见附录一 . (如果你的 JDK 版本是 1.1 ,请你加上 -jni 参数)
先编译文件 ( 此时你应该在 ../ java2c/testdll 目录下 )
javac javatest.java
利用 javah 生成的头文件 ( 此时候你应该在 ../ 目录下 )
javah java2c.testdll. javatest
 
生成的头文件为 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:    execute
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_java2c_testdll_javatest_execute
 (JNIEnv *, jclass);
 
#ifdef __cplusplus
}
#endif
#endif
 
我们看到了它将 Java 的函数翻译成了 C/C++ 语言函数声明 , 其中的参数也做了相应的转换声明 .
还有我们看到了所有的函数被强制变成了 C 的函数名字生成方式 .
JNIEXPORT jint JNICALL Java_java2c_testdll_javatest_execute
 (JNIEnv *, jclass);
JNIEnv 为环境参数
Jclass 为类参数,这些都是系统自动加载上去的,他们的作用很大 , 后面我们再介绍 .
 
下面我们利用这个函数声明写出响应的 C/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_execute
 (JNIEnv* env, jclass cls){
          printf(" 你的 DLL 文件已经调用成功! ");
          return 0;
};
 
将以上的代码进行编译 , 并将其纳入动态加载库 .
如果你在 Linux 下的 Gnu C 编译器 , 你可以使用下面的命令 :
Gcc –c –fPIC –I/usr/local/jdk/include/ -I/jdk/include/linux  java2c_testdll_javatest.cpp
Gcc –shared -o lib java2c_testdll_javatest.so java2c_testdll_javatest.o
如果是 Solaris Sun 编译器 , 可以使用 :
Cc –G –I/usr/local/jdk/include –I/usr./local/jdk/include/solaris java2c_testdll_javatest.cpp –o lib java2c_testdll_javatest.so
如果是 Windows Microsoft C++ 编译器 , 你可以使用下面的命令 :
cl –IC:/jdk/include –Ic:/jdk/include/win32 –LD java2c_testdll_javatest.cpp - java2c_testdll_javatest.dll
 
此时你可以使用这个 DLL 文件了
请将你的 DLL 文件放在 java.library.path 的路径上 .
 
 
以上是调用的结果 .
 
在写 DLL 文件的时候你可以
实现下面两个函数来实现对 DLL 的初始化和收尾工作
/* Defined by native libraries. */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved);
 
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved);
 
. Java C 连动时的数据类型分析
       刚才我们只是举了一个简单的例子来说明连动的基本方法
我们在编写真正实用的程序的时候 , 我们必然需要传递参数 .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
 
. Java C 连动参数的传递
还有我要和你讨论的是参数传递有值传递和地址 ( 还有引用传递 ) 传递的两种方式 . 在它们连动时我们也要进行这两种传递的实现 .
 
我们知道 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
功能说明:
C 头文件和 Stub 文件生成器。 javah Java 类生成 C 头文件和 C 源文件。这些文
件提供了连接胶合,使 Java C 代码可进行交互。
语法:
javah [ 命令选项 ] fully-qualified-classname. . .
javah_g [ 命令选项 ] fully-qualified-classname. . .
补充说明:
javah 生成实现本地方法所需的 C 头文件和源文件。 C 程序用生成的头文件和源文件在
本地源代码中引用某一对象的实例变量。 .h 文件含有一个 struct 定义,该定义的布局
与相应类的布局平行。该 struct 中的域对应于类中的实例变量。
头文件名以及在头文件中所声明的结构名都来源于类名。如果传给 javah 的类是在某个
包中,则头文件名和结构名前都要冠以该包名。下划线 (_) 用作名称分隔符。
缺省情况下, javah 为每个在命令行中列出的类都创建一个头文件,且将该文件放在当
前目录中。用 -stubs 选项创建源文件。用 -o 选项将所有列出类的结果串接成一个单
一文件。
缺省情况下, javah 为每个在命令行中列出的类都创建一个头文件,且将该文件放在当
前目录中。用 -stubs 选项创建源文件。用 -o 选项将所有列出类的结果串接成一个单
一文件。
命令选项
-o[ 输出文件 ] 将命令行中列出的所有类的头文件或源文件串接到输出文件中。 -o -
d 两个选项只能选择一个。
-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 指定始终写输出文件 .
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值