JAVA之JNI小结

JNI 是 Java Native Interface 的缩写。 Java™ 本机接口(Java Native Interface,JNI)是一个标准的 Java API,它支持将 Java 代码与使用其余编程语言编写的代码相集成。若是您但愿利用已有的代码资源,那么可使用 JNI 做为您工具包中的关键组件 —— 好比在面向服务架构(SOA)和基于云的系统中。java

 

一、在JDK目录下的javah.exe就是能够将Java代码转化成C++代码的头文件。(注意完整类名与文件路径)ios

二、将生成的头文件复制到C++工程下,(注意:JDK目录下的include头文件也须要相应的包含到工程里面), 按照生成的函数声明来写函数实现就能够了。在cpp文件中要include这个文件。c++

#include <jni.h>这种是在系统目录下去找,本身复制进去的须要改为双引号#include "jni.h"。编程

三、编译好工程以后,就会生成dll文件了。(dll文件和exe同样,  是可执行的二进制代码)windows

 

四、生成dll后,就将其加到环境变量,方便调用。如在Java中System.loadLibrary("aaa")可调用aaa.dll架构

Eclipse在每次启动的时候会读取一次环境变量,更改环境变量以后须要重启eclipse。app

 

Java中类型与C/C++中对应关系eclipse

 

Java中的类的对应编程语言

 

Sign签名, 用来识别对应各个方法。函数

JDK下的javap.exe能输出签名。用法javap -s -p 完整类名

 

全局引用/局部引用/弱全局引用:

弱全局引用不会阻止垃圾回收器回收这个引用所指的对象。所以弱全局引用所引用的对象不必定存在。因此有必要先判断。

 

Java中多态与C++中的Virtual对应关系(父类与子类的调用):

Java中类的成员方法都是虚拟的。CallNonvirtualVoidMethod()方法来调用。

 

一个简单的例子:

Java端代码

[java] view plain copy

 

  1. package com.jni;  
  2.   
  3. import java.util.Date;  
  4.   
  5. /* 
  6.  * 2. 本地代码C++访问Java中的类与方法等. 在dll中改变了property的值, 调用了他的方法. 
  7.  */  
  8. public class NativeAccessJava  
  9. {  
  10.     //本地方法声明  
  11.     public native void nativeAccessJavaMethod();  
  12.       
  13.     //Java中的属性  
  14.     public int property=10;  
  15.   
  16.     //Java中的方法  
  17.     public int function(int a, Date date, int[] b)  
  18.     {  
  19.         System.out.println("Native C code access Java Class!");  
  20.         return 0;  
  21.     }  
  22.       
  23.     //在C代码中调用这个方法  
  24.     public double maxValue(double a,double b)  
  25.     {  
  26.         return a>b?a:b;  
  27.     }  
  28.       
  29.     //关于多态与C++中virtual函数的对应  
  30.     public Father inst = new Son();  
  31.       
  32.       
  33.     public static void main(String[] args)  
  34.     {  
  35.         NativeAccessJava nativeAccessJava = new NativeAccessJava();  
  36.         System.out.println("改变前的值是: "+nativeAccessJava.property);  
  37.   
  38.         System.setProperty("java.library.path", ".");//这里就是在改临时环境变量  
  39.         System.loadLibrary("NativeAccessObject");//NativeAccessObject.dll, 为了方便, 能够将动态连接库直接设置到环境变量里面  
  40.           
  41.         //改变值的函数是在nativeAccessJavaMethod()中写着的, 因此要先嗲用这个方法以后, 值才改变的  
  42.         nativeAccessJava.nativeAccessJavaMethod();  
  43.         System.out.println("改变后的值是: "+nativeAccessJava.property);  
  44.     }  
  45. }  

 

C++端代码

[cpp] view plain copy

 

  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include "jni.h"  
  3. /* Header for class com_jni_NativeAccessJava */  
  4.   
  5. #ifndef _Included_com_jni_NativeAccessJava  
  6. #define _Included_com_jni_NativeAccessJava  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_jni_NativeAccessJava 
  12.  * Method:    nativeAccessJavaMethod 
  13.  * Signature: ()V 
  14.  */  
  15. JNIEXPORT void JNICALL Java_com_jni_NativeAccessJava_nativeAccessJavaMethod  
  16.   (JNIEnv *, jobject);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif  


[cpp] view plain copy

 

  1. #include "com_jni_NativeAccessJava.h"  
  2. #include "windows.h"  
  3. #include <iostream>  
  4. #include <algorithm>  
  5. using namespace std;  
  6.   
  7. /************************************************************************/  
  8. /* 2. 本地C代码调用Java中的类.                                             */  
  9. /************************************************************************/  
  10. JNIEXPORT void JNICALL Java_com_jni_NativeAccessJava_nativeAccessJavaMethod(JNIEnv *env, jobject obj)  
  11. {  
  12.     jclass java_class = env->GetObjectClass(obj);//get class object  
  13.     jfieldID fieldID_prop = env->GetFieldID(java_class,"property","I");//get property id  
  14.     jmethodID methodID_func = env->GetMethodID(java_class,"function","(ILjava/util/Date;[I)I");//get method id e.g.  
  15.   
  16.     //取得Java类中属性property的值  
  17.     jint number = env->GetIntField(obj,fieldID_prop);  
  18.     cout << number<<endl; //输出取得的值, 并输出. 这个在Java调用的时候会输出.  
  19.   
  20.     //修改property的值, 改成120  
  21.     env->SetIntField(obj,fieldID_prop,120L);  
  22.   
  23.     //调用java中的方法  
  24.     jmethodID methodID_max = env->GetMethodID(java_class,"maxValue","(DD)D");//get method ID  
  25.     jdouble maxValue = env->CallDoubleMethod(obj,methodID_max,3.11,3.15);  
  26.     cout<< "the maxValue is "<<maxValue<<endl;  
  27.   
  28.     //调用java继承关系的类, 调用的是子类的func方法. 至关于Father p = nativeAccessJava.p;  p.func();  
  29.     jfieldID id_inst = env->GetFieldID(java_class,"inst","Lcom/jni/Father;");  
  30.     jobject inst = env->GetObjectField(obj,id_inst);//get Father class obj  
  31.   
  32.     jclass class_Father = env->FindClass("com/jni/Father");//get Father class  
  33.     jmethodID id_Father_func = env->GetMethodID(class_Father,"func","()V");  
  34.   
  35.     cout<<"------------默认是virtual, CallVoidMethod-------------"<<endl;  
  36.     env->CallVoidMethod(inst,id_Father_func);    //调用子类的方法  
  37.     cout<<"------------CallNonvirtualVoidMethod-------------"<<endl;  
  38.     env->CallNonvirtualVoidMethod(inst,class_Father,id_Father_func);//调用父类的方法  
  39.   
  40. }  

 

注意

Java中的int对于C++中的long型,所以要写成100L的形式。

Java中的字符是unicode,占用2个字节,而c++中站一个字节,须要扩宽,所以char就要变成L‘3’型。

关于一些变量的声明等信息,全在jni.h头文件中寻找就好了。

 

使用JNI的两个弊端

( 1)、使用JNI后JAVA程序就不能跨平台了.

(2)、Java是强类型的语言,而C++不是,写JNI时必须很是当心。

 

 

强类型语言 :

首先咱们要声明Java 语言强类型语言的重要性。首先,每一个变量有类型,每一个表达式有类型,并且每种类型是严格定义的。其次,全部的数值传递,不论是直接的仍是经过方法调用经由参数传过去的都要先进行类型相容性的检查。有些语言没有自动强迫进行数据类型相容性的检查或对冲突的类型进行转换的机制。Java 编译器对全部的表达式和参数都要进行类型相容性的检查以保证类型是兼容的。任何类型的不匹配都是错误的,在编译器完成编译之前,错误必须被改正。  若是你有C或C++的背景,必定要记住Java对数据类型兼容性的要求比任何语言都要严格。例如,在C/C++ 中你能把浮点型值赋给一个整数在Java 中则不能。另外,C语言中,在一个参数和一个自变量之间没有必然的强制的类型检查。在Java 中则有。起初你可能发现Java 的强制类型检查有点繁烦。可是要记住,从长远来讲它将帮助你减小程序出错的可能性。

相关文章
相关标签/搜索