中科院云平台架构师,专注于数字化、智能化,技术方向:云、Linux内核、AI、MES/ERP/CRM/OA、物联网、传感器、大数据、ML、微服务。
分类: 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
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
若提示没有发现
四、将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
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 , "
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类引用
//获得该类型的构造函数 函数名为
//第三个参数根据构造函数的类型设定
//例如:"(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 , "
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, "
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
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下,可以访问。