JNI常识

来源:互联网 发布:网络工程项目名称 编辑:程序博客网 时间:2024/05/22 14:11

简介:

java Native interface: native关键字表示可以调用操作系统的底层函数.
Java例子:Thread类的private native void start();
主要内容:
1、Java 通过JNI调用DLL,返回ArrayList.
2、Jsp 通过JNI调用DLL.
 
使用的开发工具:MyEclipse10.7 + java jdk1.6.0_35 + vs2010.
 
一、Java层原型方法
 
[java] view plaincopy
package com.zdd.searcher;  
  
import java.util.ArrayList;  
  
public class SearchEngine {  
    public native ArrayList query(String imgFileName);  
      
    static  
    {  
        System.loadLibrary("searchenginedll");  
    }  

[java] view plaincopy
package com.zdd.searcher;  
  
/** 
 * 查询结果项 
 * @author zdd 
 * 
 */  
public class QueryResult   
{  
    private String filePath; //  
    private float similarity; //  
      
    //构造函数  
    public QueryResult() {  
        filePath="";  
        similarity = 0.0f;  
    }  
      
    public QueryResult(String filePath, float similarity) {  
        this.filePath = filePath;  
        this.similarity = similarity;  
    }  
      
    public String toString() {  
        return "filePath: " + filePath + " similarity: " + similarity;  
    }  
      
    public String getFilePath() {  
        return filePath;  
    }  
    public void setFilePath(String filePath) {  
        this.filePath = filePath;  
    }  
    public float getSimilarity() {  
        return similarity;  
    }  
    public void setSimilarity(float similarity) {  
        this.similarity = similarity;  
    }  


二、生成.h文件
[cpp] view plaincopy
\src>javac com/zdd/searcher/SearchEngine.java  
  
\src>javah com.zdd.searcher.SearchEngine 

三、使用.h写dll项目
使用vs新建win32 dll项目,将上述生成的com_zdd_searcher_SearchEngine.h文件导入项目。
[cpp] view plaincopy
/* DO NOT EDIT THIS FILE - it is machine generated */  
#include   
/* Header for class com_zdd_searcher_SearchEngine */  
  
#ifndef _Included_com_zdd_searcher_SearchEngine  
#define _Included_com_zdd_searcher_SearchEngine  
#ifdef __cplusplus  
extern "C" {  
#endif  
/* 
 * Class:     com_zdd_searcher_SearchEngine 
 * Method:    query 
 * Signature: (Ljava/lang/String;)Ljava/util/ArrayList; 
 */  
JNIEXPORT jobject JNICALL Java_com_zdd_searcher_SearchEngine_query  
  (JNIEnv *env, jobject _obj, jstring _imgFileName);  
  
#ifdef __cplusplus  
}  
#endif  
#endif 


若提示没有发现,则在VC++ Directories ->Include中添加JNI头文件:..\Java\jdk1.6.0_35\include和..\Java\jdk1.6.0_35\include\win32。
 
四、将c++中的vector向量通过Native层以ArrayList集合对象的方式返回给Java.
 
[cpp] view plaincopy
SearchEngine *searcher = NULL;  
  
/* 
 * Class:     com_zdd_searcher_SearchEngine 
 * Method:    query 
 * Signature: (Ljava/lang/String;)Ljava/util/ArrayList; 
 */  
JNIEXPORT jobject JNICALL Java_com_zdd_searcher_SearchEngine_query  
  (JNIEnv *env, jobject _obj, jstring _imgFileName)  
{  
  
    if(searcher == NULL)  
        searcher = new FaceImageSearch();  
  
    //获取查询结果  
    vector results;  
    searcher->query(jstringTostring(env, _imgFileName), results);  
  
  
    jclass list_cls = env->FindClass("Ljava/util/ArrayList;");//获得ArrayList类引用  
    if(list_cls == NULL)    
    {    
        std::cout << "list_cls is null \n" ;    
    }    
    jmethodID list_costruct = env->GetMethodID(list_cls , "","()V"); //获得得构造函数Id    
  
  
    jobject list_obj = env->NewObject(list_cls , list_costruct); //创建一个Arraylist集合对象    
  
  
    //或得Arraylist类中的 add()方法ID,其方法原型为: boolean add(Object object) ;    
    jmethodID list_add  = env->GetMethodID(list_cls,"add","(Ljava/lang/Object;)Z");     
  
    jclass qr_cls = env->FindClass("Lcom/zdd/searcher/QueryResult;");//获得QueryResult类引用    
  
    //获得该类型的构造函数  函数名为 返回类型必须为 void 即 V    
    //第三个参数根据构造函数的类型设定  
    //例如:"(Ljava/lang/String;F)V"表示Java中方法为void xxx(String, float)其中,xxx表示函数名  
    //-------------------------------------------------  
    //基本JNI域描述符  
    //  Z   --  boolean  
    //  B   --  byte  
    //  C   --  char  
    //  S   --  short  
    //  I   --  int  
    //  J   --  long  
    //  F   --  Float  
    //  D   --  double  
    //引用类型的描述符  
    //  Object  --  Ljava/lang/Object;   //注意此处的分号(;)是JNI的一部分,不能省。  
    //  String  --  Ljava/lang/String;  
    //  int[]   --  [I  
    //  float[] --  [F  
    //  String[] -- [Ljava/lang/String;  
    //方法表示示例  
    // int f (int i, Object object) -- (ILjava/lang/Object;)I  
    //void set (byte[ ] bytes) --  ([B)V  
    jmethodID qr_costruct = env->GetMethodID(qr_cls , "", "(Ljava/lang/String;F)V");    
  
  
    for(unsigned int i = 0; i < results.size(); i++)  
    {  
        //通过调用该对象的构造函数来new 一个 QueryResult实例    
        jobject qr_obj = env->NewObject(qr_cls , qr_costruct, stringToJstring(env, results[i].imagePath.c_str()), results[i].similarity);  //构造一个对象  
  
        env->CallBooleanMethod(list_obj , list_add , qr_obj); //执行Arraylist类实例的add方法,添加一个QueryResult对象    
    }  
  
    return list_obj;  

五、char*和jstring相互传化
[cpp] view plaincopy
//jstring to char*  
char* jstringTostring(JNIEnv* env, jstring jstr)  
{  
    char* rtn = NULL;  
    jclass clsstring = env->FindClass("java/lang/String");  
    jstring strencode = env->NewStringUTF("utf-8");  
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");  
    jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);  
    jsize alen = env->GetArrayLength(barr);  
    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  
    if (alen > 0)  
    {  
        rtn = (char*)malloc(alen + 1);  
        memcpy(rtn, ba, alen);  
        rtn[alen] = 0;  
    }  
    env->ReleaseByteArrayElements(barr, ba, 0);  
    return rtn;  
}  
  
//char* to jstring  
jstring stringToJstring(JNIEnv* env, const char* pat)  
{  
       jclass strClass = env->FindClass("Ljava/lang/String;");  
       jmethodID ctorID = env->GetMethodID(strClass, "", "([BLjava/lang/String;)V");  
       jbyteArray bytes = env->NewByteArray(strlen(pat));  
       env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);  
       jstring encoding = env->NewStringUTF("utf-8");  
       return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);  

其它代码略。
六、编译dll,并将其放项目目录下(和src平行) 在java中使用如下代码测试
[cpp] view plaincopy
package com.zdd.searcher;  
  
import java.util.ArrayList;  
  
public class DllTest {  
  
    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        SearchEngine se = new SearchEngine();  
          
        ArrayList lists = se.query("");  
          
        for(int i = 0; i < lists.size(); i++)  
        {  
            System.out.println(lists.get(i).getFilePath());  
        }  
          
        System.out.println("Done.");  
    }  
  


七、在JSP中使用JNI调用dll
JSP本身分为bean的src目录和WebRoot的脚本目录,而我们的dll需要在src下的类中调用,于是遇到了将DLL和资源文件放置到什么地方的问题。并且使用MyEclipse自带的tomcat,不存在../tomcat/bin目录。
最后解决方法:将DLL放置在..\Java\jdk1.6.0_35\bin下,可以访问。

0 0
原创粉丝点击