在C/C++中调用Java的方法一般分为五个步骤:初始化虚拟机、获取类、获取类的方法、创建类对象、调用方法和退出虚拟机。
以下摘自:http://blog.csdn.net/sunchaoenter/article/details/6598719
Java代码:
-
package
jni.test;
-
-
public
class
Demo {
-
-
public
static
int
COUNT =
8
;
-
-
public
String msg;
-
private
int
[] counts;
-
-
public
Demo() {
-
this
(
“缺省构造函数”
);
-
}
-
-
public
Demo(String msg) {
-
System.out.println(
“<init>:”
+ msg);
-
this
.msg = msg;
-
this
.counts =
null
;
-
}
-
-
public
String getMessage() {
-
return
msg;
-
}
-
-
public
int
[] getCounts() {
-
return
counts;
-
}
-
-
public
void
setCounts(
int
[] counts) {
-
this
.counts = counts;
-
}
-
-
public
void
throwExcp()
throws
IllegalAccessException {
-
throw
new
IllegalAccessException(
“exception occur.”
);
-
}
-
}
上面的代码很好理解,我相信你能看的懂,我就不说了。
下面是C语言代码,里面有注释,这里先不详细说明,主要先跑起来再说:
-
#include <stdio.h>
-
#include <jni.h>
-
#include <stdlib.h>
-
#include <iostream.h>
-
int
main() {
-
// 定义用到的变量
-
int
res;
-
JavaVM *jvm;
-
JNIEnv *env;
-
JavaVMInitArgs vm_args;
-
JavaVMOption options[3];
-
vm_args.version;
-
-
// 设置初始化参数
-
options[0].optionString =
“-Djava.compiler=NONE”
;
-
// classpath有多个时,用”;”分隔,UNIX下以”:”分割。
-
options[1].optionString =
“-Djava.class.path=.”
;
-
// 用于跟踪运行时的信息
-
options[2].optionString =
“-verbose:jni”
;
-
// 版本号设置不能漏
-
vm_args.version = JNI_VERSION_1_6;
-
vm_args.nOptions = 3;
-
vm_args.options = options;
-
vm_args.ignoreUnrecognized = JNI_TRUE;
-
// 1.初始化虚拟机
-
res = JNI_CreateJavaVM(&jvm, (
void
**)&env, &vm_args);
-
if
(res < 0)
-
{
-
fprintf(stderr,
“Can’t create Java VM\n”
);
-
exit(1);
-
}
-
// 2.获取类
-
jclass cls = env->FindClass(
“jni/test/Demo”
);
-
// 3.获取类的方法
-
jmethodID mid= env->GetMethodID(cls,
“getMessage”
,
“()Ljava/lang/String;”
);
-
// 获取Java的构造方法
-
jmethodID con=env->GetMethodID(cls,
“<init>”
,
“(Ljava/lang/String;)V”
);
-
jstring strinit = env->NewStringUTF(
“Still is coding!”
);
-
jvalue arg[1];
-
arg[0].l = strinit;
-
//env->AllocObject(cls);
-
// 4.创建类的对象
-
jobject obj = env->NewObjectA(cls,con,arg);
-
// 调用对象的方法
-
jstring msg = (jstring)env-> CallObjectMethod(obj, mid);
-
-
cout<<msg<<endl;
-
char
*str=(
char
*)env->GetStringUTFChars(msg,JNI_FALSE);
-
printf(
“%s===”
,str);
-
// 5.退出虚拟机
-
jvm->DestroyJavaVM();
-
fprintf(stdout,
“Java VM destory.\n”
);
-
return
0;
-
}
把以上C语言代码用VC6.0打开,然后编译,下面问题就来了,我们一个一个解决。
编译的时候首先会出现如下问题:
错误很明显,我们上面包含了jni.h
,但是没找到。这是需要设置一下
VC
。
Tools->Options->Directories,
添加
JDK
安装目录下的两个目录,如图:
同时在
Library files
中添加
JDK
下面的
LIB
目录,如下图:
点击
OK
完成,重新编译。
好,新问题又来了,看下面描述:
也很明显,说明没有找到
jvm.lib
。继续设置
VC
,
Project->Settings->Link->Object/library modules
中把上述路径替换为本机实际安装
JDK
中的
jvm.lib
目录,添加完后如下图:
点击
OK
后重新编译,呵呵,又来问题了,我很高兴啊。
这个问题在网上查了一下,原来是我
JDK
安装在
Program Files
下的问题,因为
Program Files
路径中有一个空格,真郁闷,没办法,只好重装
JDK
,注意安装目录中不能再有空格了。安装完了,按照上面出现的问题再重新设置一下
VC
,然后编译,没问题,运行,哇靠,又是一个问题:
这个问题可是花了我大半天时间才搞定的,但其实做法很简单。
看错描述,是没找到
jvm.dll
,网上很多人说直接找到这个文件把它拷贝到当前目录。但是这种方法不可取,因为
jvm.dll
这个东东还会依赖其他的文件的,而且它找其它所依赖的文件是通过相对路径找的,你直接就搞这么一个文件出来,其它的也找不到啊。所以这里有一个很好的解决方案,就是把
D:\Java\jdk1.6.0_23\jre\bin\client
这个
JDK
下的路径加入
Path
环境变量,
加完之后记得重新用
VC
打开
CPP
文件,这个很重要
,否则,这个问题还是没有解决。
点击编译,运行,如果出现如下画面,
OK
,恭喜你,
C
语言调用
Java
成功了,下面要做的就是去看代码,并且了解运行的机理了,这个我就不多说了。
java 调用 c/c++
1.使用native定义方法 本地方法
2.编译得到字节码文件
3.使用javah -jni xxx命令生成C语言头文件
4.C语言实现头文件定义的方法,再用ndk打包城.so文件
5.java程序中使用loadlibry方法加载库文件
问题找不到文件:
使用Javah 可以获取您的 Java 源文件并生成 C/C++头文件,其中包含您的 Java 代码中所有本地方法(native方法)的 JNI 存根(stub,C头文件)。如果您正在生成一个类的 JNI 存根,而且您已经把这个类定义为包的一部分,那么您 必须指定完全限定的类名。
下面举例说明:
使用eclipse建立一个工程假设工程路径为$ProjectPath,并且你已经定义了一个类,并且带包名:cn.com.comit.jni
—————————-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
|
—————————-
eclipse会自动帮你编译出一个字节码文件HelloJni.class,路径是$ProjectPath\bin\cn\com\comit\jni,很可能你会先cd到.class的目录这么做:
>
cd $ProjectPath\bin\cn\com\comit\jni
>$ProjectPath\bin
javah HelloJni
发现执行出错:
错误:无法访问 HelloJni
错误的类文件: .\HelloJni.class
类文件包含错误的类: cn.com.comit.jni.HelloJni
请删除该文件或确保该文件位于正确的类路径子目录中。
看来是路径有问题咯。那改成
javah cn.com.comit.jni.HelloJni
再次运行,发现还是错误:
错误:无法访问 cn.com.comit.jni.HelloJni
未找到 cn.com.comit.jni.HelloJni 的类文件
javadoc: 错误 – 找不到类 cn.com.comit.jni.HelloJni。
如果是android工程需要用户切换的目录为
$ProjectPath\bin\classes\文件夹
怎么才能解决这个问题呢?其实只要cd到包的上一级目录(我们这里是$ProjectPath\bin)在运行下面的命令就搞定了:
javah -classpath . cn.com.comit.jni.HelloJni
看一下生成的C头文件:
1
2
3
4
5
|
|
1
2
|
|
1
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
|
android.mk文件的简介:
http://www.cnblogs.com/luxiaofeng54/archive/2011/08/13/2137577.html