但是需要注意的是javah命令对Android编译生成的类文件并不能正常工作。如果对于Android的JNI要想生成C\C++头文件的话,可能只有先写个纯的java代码来进行JNI定义,接着用JDK编译,然后再用javah命令生成JNI的C\C++头文件。当然你也可以不用javah命令,直接手写JNI的C\C++头文件。
使用javah或javah -help将看到javah命令的语法信息。
实例1:
javah
Usage: javah [options] <classes>
where [options] include:
-help Print this help message and exit
-classpath <path> Path from which to load classes
-bootclasspath <path> Path from which to load bootstrap classes
-d <dir> Output directory
-o <file> Output file (only one of -d or -o may be used)
-jni Generate JNI-style header file (default)
-version Print version information
-verbose Enable verbose output
-force Always write output files
<classes> are specified with their fully qualified names (for instance, java.lang.Object).
<classes>参数
和javac命令相似,有两种方法可以指定需要javah命令把JNI方法转化成C\C++头文件的类文件名
一种是直接给出要操作的类文件
如果源文件数量少,可以用这种方式,在命令行上列出文件名即可。文件与文件之间用空格非分开就可以了。
另一种是通过@files的形式
可以把要操作的java类文件名列在一个文件,文件名之间用空格或回车进行分割。然后在javah命令行中,
可以用‘@‘ 字符加上包含需要把JNI方法转化成C\C++头文件的类文件名的文件名来指定需要把哪些java类文件的JNI方法转化成C\C++头文件。
因为javah当遇到以 `@‘ 字符,它就会把该字符后的文件所列出的所有java类文件的JNI方法转化为C\C++头文件。这种形式适用于java类文件很多的情况。
-bootclasspath和-classpath
javah操作是针对类文件,-bootclasspath和-classpath就是指定在哪里进行类文件搜索。
JDK搜索类文件先后顺序如下:Bootstrap classes,User classes
Bootstrap默认的是JDK自带的jar或zip文件,它包括jre\lib下rt.jar等文件,JDK首先搜索这些文件.
可以通过-bootclasspath来设置它。文件之间用分号";"进行分割。
User classes搜索顺序为当前目录、环境变量 CLASSPATH、-classpath。
它们用于告知JDK搜索类文件根目录名、jar文档名、zip文档名,用分号";"进行分隔。
例如当你自己开发了公共类并包装成一个common.jar包,在使用 common.jar中的类时,就需要用-classpath common.jar 告诉JDK从common.jar中查找该类,否则JDK就会抛出java.lang.NoClassDefFoundError异常,表明未找到类定义。
使用-classpath后JDK将不再使用CLASSPATH中的类搜索路径,如果-classpath和CLASSPATH都没有设置,则JDK使用当前路径(.)作为类搜索路径。
推荐使用-classpath来定义JDK要搜索的类路径,而不要使用环境变量CLASSPATH的搜索路径,以减少多个项目同时使用CLASSPATH时存在的潜在冲突。例如应用1要使用a1.0.jar中的类G,应用2要使用 a2.0.jar中的类G,a2.0.jar是a1.0.jar的升级包,当a1.0.jar,a2.0.jar都在CLASSPATH中,JDK搜索到第一个包中的类G时就停止搜索,如果应用1应用2的虚拟机都从CLASSPATH中搜索,就会有一个应用得不到正确版本的类G。
javah命令是针对类文件中的,你肯定需要要把你要操作的类文件的根目录包含在搜索路径中,对于包文件(Jar或zip)形式的类文件,它的根目录就是包文件。另外这里的-bootclasspath和-classpath与java或javac命令都很相似,但是javah命令没有用来设置Extension classes的-extdirs参数选项,有点奇怪!还有这里的"-classpath"也不能缩写成"-cp"
-d 和-o
这两个参数用于设置生成的C\C++头文件的指定,该两参数选项不能同时使用,-d是为<classes>中的每个有JNI方法的java类都生成一个头文件,并存放在-d指定的目录中,-o则是生成的所有JNI方法的头文件都放在-o指定的文件中。
-version
显示当前javah的版本号.
实例2:
javah -version
javah version "1.6.0_11"
-jin
表示用于生成JNI风格的C\C++头文件,默认该参数就是开启的。不过应该不能关闭参数。
-verbose
开启了该参数,将显示javah命令搜索和装置类文件的详细过程。
实例2:
文件1 src\com\robin\Hello.java
package com.robin;
public class Hello{
void sayHello()
{
System.out.println(getHelloStringFromJni());
}
native String getHelloStringFromJni();
}
文件2 src\com\robin\People.java
package com.robin;
public class People
{
String name;
native String getNameFromJni();
}
文件3 com\hubin\Util.java
package com.hubin;
public class Util{
public final static String getString()
{
return "Hi";
}
native static String getStringFromJni();
}
文件4 src.txt
src\com\robin\Hello.java
src\com\robin\People.java
src\com\hubin\Util.java
文件5 classNames.txt
com.robin.Hello com.robin.People
com.hubin.Util
运行命令编译
javac -d classes @src.txt
如果运行以下javah命令
javah -d h -classpath classes -jni @classNames.txt
命令结束后,你将在h目录先看到如下文件:
com_robin_Hello.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_robin_Hello */
#ifndef _Included_com_robin_Hello
#define _Included_com_robin_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_robin_Hello
* Method: getHelloStringFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_robin_Hello_getHelloStringFromJni
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
com_robin_People.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_robin_People */
#ifndef _Included_com_robin_People
#define _Included_com_robin_People
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_robin_People
* Method: getNameFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_robin_People_getNameFromJni
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
com_hubin_Util.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_hubin_Util */
#ifndef _Included_com_hubin_Util
#define _Included_com_hubin_Util
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hubin_Util
* Method: getStringFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_hubin_Util_getStringFromJni
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
如果运行以下命令
javah -o h\MyJni.h -classpath classes -jni @classNames.txt
将在h目录下看到MyJni.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_robin_Hello */
#ifndef _Included_com_robin_Hello
#define _Included_com_robin_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_robin_Hello
* Method: getHelloStringFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_robin_Hello_getHelloStringFromJni
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
/* Header for class com_robin_People */
#ifndef _Included_com_robin_People
#define _Included_com_robin_People
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_robin_People
* Method: getNameFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_robin_People_getNameFromJni
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
/* Header for class com_hubin_Util */
#ifndef _Included_com_hubin_Util
#define _Included_com_hubin_Util
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hubin_Util
* Method: getStringFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_hubin_Util_getStringFromJni
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
可以开启-verbose参数来查看javah命令搜索和载人类文件的过程。
比如:
D:\project\test>javah -o h\MyJni.h -classpath classes -jni -verbose @classNames.txt
[ Search Path: C:\jdk1.6.0\jre\lib\resources.jar;C:\jdk1.6.0\jre\lib\rt.jar;C:\j
dk1.6.0\jre\lib\sunrsasign.jar;C:\jdk1.6.0\jre\lib\jsse.jar;C:\jdk1.6.0\jre\lib\
jce.jar;C:\jdk1.6.0\jre\lib\charsets.jar;C:\jdk1.6.0\jre\classes\classes ]
[No need to update file h\MyJni.h]
[search path for source files: classes]
[search path for class files: C:\jdk1.6.0\jre\lib\resources.jar,C:\jdk1.6.0\jre\
lib\rt.jar,C:\jdk1.6.0\jre\lib\sunrsasign.jar,C:\jdk1.6.0\jre\lib\jsse.jar,C:\jd
k1.6.0\jre\lib\jce.jar,C:\jdk1.6.0\jre\lib\charsets.jar,C:\jdk1.6.0\jre\classes,
C:\jdk1.6.0\jre\lib\ext\dnsns.jar,C:\jdk1.6.0\jre\lib\ext\localedata.jar,C:\jdk1
.6.0\jre\lib\ext\sunjce_provider.jar,C:\jdk1.6.0\jre\lib\ext\sunmscapi.jar,C:\jd
k1.6.0\jre\lib\ext\sunpkcs11.jar,classes]
[loading classes\com\robin\Hello.class]
[loading classes\com\robin\People.class]
[loading classes\com\hubin\Util.class]
[loading java\lang\Object.class(java\lang:Object.class)]
[loading java\lang\String.class(java\lang:String.class)]
[loading java\lang\Throwable.class(java\lang:Throwable.class)]
[loading java\lang\Class.class(java\lang:Class.class)]
[done in 312 ms]