JNI学习笔记,含VS配置x64平台的问题

本文详细介绍了如何在Java程序中调用C++函数,并在C++端实现相应的Java接口,包括生成C++头文件、设置编译环境、编写实现代码以及调试过程。此外,还提供了在Java中使用C++类的技巧,以及如何解决调试过程中遇到的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[size=medium]1、来个java程序,本地方法前加[color=red]native[/color]关键字[/size]
public class HelloWorld_20111226 {
public static native void printHelloWorld();

public static native int add(int a, int b);

static {
System.loadLibrary("TestJNI_201112");

}

public static void main(String[] args) {
printHelloWorld();
int sum = add(1, 2);
System.out.println(sum);
}
}


[size=medium]2.生成C++头文件[/size]
命令行下 javah 类名(在.class的根路径下  包名.类名,无需后缀)

[size=large][color=red]简单方法见[/color][/size][url]http://cherishlc.iteye.com/blog/1326893[/url]
生成的头文件如下
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld_20111226 */

#ifndef _Included_HelloWorld_20111226
#define _Included_HelloWorld_20111226
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld_20111226
* Method: printHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_120111226_printHelloWorld
(JNIEnv *, jclass);

/*
* Class: HelloWorld_20111226
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_HelloWorld_120111226_add
(JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif



[size=medium]3.写C++端的实现[/size]
新建vs的win32工程:
[img]http://dl.iteye.com/upload/attachment/612621/50efbc43-2ebb-3024-a1fa-fbef8ac53c3b.png[/img]

接下来选择DLL工程:
[img]http://dl.iteye.com/upload/attachment/612623/397a0540-b8ab-3b84-8167-089852011ec0.png[/img]
加入刚刚生成的头文件;写实现函数的cpp文件,写导出函数的.def文件:
[img]http://dl.iteye.com/upload/attachment/612625/1cdec743-5653-385d-98c4-fa5cb2d17ea0.png[/img]


#include "HelloWorld_20111226.h"
#include <iostream>

JNIEXPORT void JNICALL Java_HelloWorld_120111226_printHelloWorld( JNIEnv *, jclass )
{
std::cout<<"Hello world"<<std::endl;
}

JNIEXPORT jint JNICALL Java_HelloWorld_120111226_add( JNIEnv *, jclass, jint a, jint b)
{
return a+b;
}


[size=large][color=red]注意:64位的JVM需要64位的DLL!![/color][/size]
设置方法: VS下设置如下:
点击工具栏上的配置编译的平台的工具栏的向下的箭头:
[img]http://dl.iteye.com/upload/attachment/612629/83fdcaf5-9758-337e-b795-bc69ff517c31.png[/img]
选择所需工程,点击之:
[img]http://dl.iteye.com/upload/attachment/612633/d0bd690d-011f-32b5-9b91-92550cfacf11.png[/img]
选择x64架构,点ok,搞定!!

[size=large][color=red]注意:jni.h的路径要加进来,你懂的:[/color][/size]

[img]http://dl.iteye.com/upload/attachment/612637/f594da7f-17bf-3ebd-b433-2a91f4eefe7c.png[/img]

[size=large][color=red]注意:还是老老实实用.def文件定义导出函数吧!不这样函数名可能会被编译器改掉!!![/color][/size]
//main.def文件如下:
LIBRARY "TestJNI_201112"
EXPORTS
Java_HelloWorld_120111226_printHelloWorld
Java_HelloWorld_120111226_add
Java_LC_TestJNI_printInt
Java_LC_TestJNI_printIntArray



[size=medium]4.编译,将生成的dll文件考到当前路径下(在Eclipse中运行即为工程文件所在路径),运行java程序,一切OK[/size]
[size=large][color=red]注意:别忘了java类里要加载DLL“static {System.loadLibrary("TestJNI_201112");}”! 不带后缀![/color][/size]

[size=medium]5.进阶:[/size]
Jni中C++和Java的参数传递[url]http://www.blogjava.net/china-qd/archive/2006/04/29/44002.html[/url]
Java Native Interface Specification:[url]http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html[/url]

[size=medium]6.在Java中用C++的类:[/size]
只是想到一个小技巧:
[size=medium][color=red]声明一个所需类的全局指针变量,需要时new一下, 不需要时delete之;缺点是只能用一个啊! 当然用个vector之类的记录当前活动的自然可以,可是多了一层,速度受影响吧!![/color][/size]
部分代码如下:
#include "Maxflow/LCEnergyMinimize_Graph.h"
#include "GraphMinimization_GraphCut.h"
typedef LCEnergyMinimize_Graph<jint,jlong> GraphIntLong;

GraphIntLong* g;
JNIEXPORT void JNICALL Java_GraphMinimization_GraphCut_generateGraph( JNIEnv *, jobject )
{
if(g!=NULL)delete g;
g=new GraphIntLong();
}
/*
* Class: GraphMinimization_GraphCut
* Method: releaseGraph
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_GraphMinimization_GraphCut_releaseGraph
(JNIEnv *, jobject){
if(g!=NULL)delete g;
g=NULL;
}

/*
* Class: GraphMinimization_GraphCut
* Method: addVariable
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_GraphMinimization_GraphCut_addVariable
(JNIEnv *, jobject, jint num){
return g->addVariable(num);
}

[size=medium]7.调试记录:[/size]
一开始程序经常崩溃,只说是C++端的错误。
后来看到下面的error log,至少知道是Graph<long,long,__int64>::add_edge出错,后来发现其中有assert语句,检查下标越界,感觉是自己写的时候下标越界了,在java里调用add_edge的地方增添了句检查下标越界的操作,越界时抛出异常:throw new RuntimeException("x = "+x+"\ty = "+y+"\t varNum = "+getVarNum());
果然问题出在下标上!!!
后来发现自己存不同下标的变量太多,有一处弄混了!!
Stack: [0x0000000001ca0000,0x0000000001da0000],  sp=0x0000000001d9f750,  free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [MaxflowJNIInterface.dll+0x1a74] Graph<long,long,__int64>::add_edge+0x74

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J GraphMinimization.GraphCut.addTerm2(IIIIII)V
J app.StereoCorrespodenceUsingGraphCut.generateStereoCorrespodenceGraph(Llc/util/image/IntPair;)LGraphMinimization/GraphCut;
j app.StereoCorrespodenceUsingGraphCut.calculate()V+52
j app.StereoCorrespodenceUsingGraphCut.main([Ljava/lang/String;)V+62
v ~StubRoutines::call_stub
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值