在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
|
package
cn.com.comit.jni;
public
class
HelloJni {
public
native
void
displayHelloJni();
static
{
System.loadLibrary(
""
);
}
/**
* @param args
*/
public
static
void
main(String[] args) {
// TODO Auto-generated method stub
new
HelloJni().displayHelloJni();
}
}
|
----------------------------
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
|
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class cn_com_comit_jni_HelloJni */
//避免重复包含头文件
|
1
2
|
#ifndef _Included_cn_com_comit_jni_HelloJni
#define _Included_cn_com_comit_jni_HelloJni
|
1
|
//c++编译环境中才会定义__cplusplus (plus就是"+"的意思
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#ifdef __cplusplus
extern
"C"
{
//告诉编译器下面的函数是c语言函数(因为c++和c语言对函数的编译转换不一样,主要是c++中存在重载)
#endif
/*
* Class: cn_com_comit_jni_HelloJni
* Method: displayHelloJni
* Signature: ()V
*/
JNIEXPORT
void
JNICALL Java_cn_com_comit_jni_HelloJni_displayHelloJni
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
|
android.mk文件的简介:
http://www.cnblogs.com/luxiaofeng54/archive/2011/08/13/2137577.html