package cn.itcast;
public calss TestNative {
public native void sayHello();
public static void main(String[] arg){
}
}```
2. 用javah.exe生成包含native方法的C/C++头文件
javah -jni(默认)
javah cn.itcast.TestNative //由类名执行生成C/C++头文件
生成的头文件内容:JNIEXPORT void JNICALL Java_cn_itcast_TestNative_SayHello (JNIEnv*, jobject)
3. 参照生成的头文件生成C/C++源文件
在VS下:Win32工程-->DLL-->空的工程-->结束
把生成的头文件引入到C++工程中,从JDK/include和include/win32中
jni.h和jni_md.h文件,然后创建一个新的C++源文件
```java
#include
#include "cn_itcast_TestNative.h"
JNIEXPORT void JNICALL Java_cn_itcast_TestNative_sayHello
(JNIEnv* env, jobject obj){
count<
4. 返回Java写Java调用dll代码部分
在主函数中:
System.loadLibrary("nativeCode")//写入你生成的dll文件名,但不要写“.dll”java会自动识别Windows还是Linux系统
new TestNative().sayHello();
运行一下,结果:
Hello world
----
##使用JNI的两个弊端
1. 使用JNI,这个Java Application就不跨平台了,如果要移植到其他平台那么native代码就要重新编写,编译。
2. Java是强类型语言,C/C++不是,因此使用JNI要格外小心
**总之,尽量少用JNI**
本地代码访问Java代码
* 在本地调用的C/C++函数中也可以反过来访问Java程序中的类
* javah工具生成C/C++函数生命中,可以看到两个参数
> JNI* env 实际上代表了Java环境,通过JNIEnv*指针,就可以对Java端代码进行操作,例如:创建Java类的对象,调用Java对象的方法,获取Java对象属性等
* JNIEnv类中有很多函数可以用。
NewObject/NewString/New Array
Get/SetField
CallMethod /CallStaticMethod 等许多函数某个类型的变量
> jobject* obj 被定义为_jobject
* Java操作对象为引入操作,而C/C++中使用指针对对象操作
* jobject* obj 指向一个Java对象的引用,这个对象引用是Java中Native方法所对应的对象
<1>若native方法非静态,它指向native方法所对应的实例
<2>若native方法静态(static)那么它指向native所对应的class对象:Class.class
### Java类型在C/C++中的映射关系
| Java | 本地类型 | JNI定义的别名(jni.h中定义) |
| ------- |:------------------:| -------:|
| int | long | jint/jsize |
| long | _int64 | jlong |
| byte | signed char | jbyte |
| boolean | unsigned char | jboolen |
| char | signed short | jchar |
| short | short | jshort |
| float | float | jfloat |
| double | double | jdouble |
| Object | _jobject* | jobject |
### jclass的取得
typedef _jclass* jclass
为了使C/C++使用Java类,Jni.h头文件中专门定义了jclass类型表示Java中的class类
JNIEnv类中有如下几个简单的函数可以取得jclass:
- jclass FindClass(const char * clsName);
- jclass GetObjectClass (jobject obj);
- jclass GetSuperClass (jclass obj);
Findclass会在classpath系统环境变量下寻找类
传入完整的类名,注意包与包之间是'/'而不是'.'来分隔
如:jclass cls_string=env->FindClass("Java/lang/String")
C/C++访问Java端代码,一个常用的应用就是获取类的属性和调用类的方法,为了在C/C++中表示属性和方法JNI在jni.h头文件中定义了jfieldID,jmethodID分别代表Java端属性和方法
我们在访问或设置Java属性时,必须先取得代表Java属性的jfieldID,然后才可以在本地代码进行Java属性操作;同样,需要使用Java端方法时,也是要取得代表该方法的jmethodID才能对Java方法调用。
使用JNIEnv的GetFieldID/GetMethodID GetStaticFieldID/GetStaticMethodID 来取得相应的jfieldID和jmethodID
* 方法原型:GetFieldID/GetStaticFieldID/GetMethodID/GetStaticMethodID(jclass clazz,const char* name,const char* sign)
如:env->GetMethodID(data_clazz,"","()V")
* Sign签名,用来表示取得的属性/方法的类型
| 类型 | 相应签名 |
| ------- |:------------------:|
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | L |
| float | F |
| double | D |
| void | V |
| object | L 用“/”分隔包的完整类名;如:Ljava/lang/String; |
| Array(数组) | [Sign 如[L [Ljava/lang/object; |
| Method | (Type)V 若指定“(I)V” 则取回 void function(int)的jmethodID
若指定“(D)V”则取回void function(double)的jmethodID|