Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7096626
  • 博文数量: 703
  • 博客积分: 10821
  • 博客等级: 上将
  • 技术积分: 12042
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-02 10:41
个人简介

中科院云平台架构师,专注于数字化、智能化,技术方向:云、Linux内核、AI、MES/ERP/CRM/OA、物联网、传感器、大数据、ML、微服务。

文章分类

全部博文(703)

分类: Java

2013-11-26 19:55:57

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下,可以访问。

阅读(3616) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~