0
点赞
收藏
分享

微信扫一扫

C++ 与 JAVA调用问题


c++调用java其实并不复杂,分为几个步骤:

 

在说调用之前,我们先来看看我们需要调用的java类

public class Test {


Java代码   ​​​​

public

}

public
return
}

public
System.out.println("invoke getObject ok***");
new
to.setName("name");
to.setPwd("pwd");
return
}

public void
System.out.println("%%% invoke test ok***");
}


这是一个很简单的类,他有一个无参的构造函数,有三个方法,一个带有String返回值的方法,一个是返回一个我们自定义的对象TestObject,另外还有一个没有返回值的test方法。

接下来是TestObject类

 



Java代码   ​​​​

public class
public

public

public
return
}

public void
this.name = name;
}

public
return
}

public void
this.pwd = pwd;
}

public void
System.out.println("%%%call back ok*** cotnent is: " + content);
System.out.println("name is: " + name);
System.out.println("pwd is: " + pwd);
}

}


 

也是一个很简单的类,有两个属性,还有一个回调函数,主要是想演示一下我们如在C++中获取该对象以后,进行回调,这也是我们经常会遇到的问题。

 

上面看了我们的java测试类,接下来,我们来具体看看如何进行调用

 

创建jvm

我们首先需要初始化一些jvm的参数,然后创建出jenv和jvm以便我们之后的调用

 



Cpp代码   ​​​​


JavaVMOption options[1];  
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
long
jclass testCls;
jmethodID testMid;
jobject testJobj;
jobject tookitReturnObj;
//设置Java类的路径
options[0].optionString = "-Djava.class.path=. ;D:\\workspace\\my\\JniTest\\jnitest.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
void**)&env, &vm_args);


 


 

加载调用的java类

当我们创建完jvm后,会得到一个返回值,如果为0说明创建成功,如果否则创建失败。

当我们成功创建完jvm后,接下来我们找到需要调用的java类

 



Cpp代码   ​​​​

• •   
• if
• {
• testCls = env->FindClass("jni/test/Test");
• }


 

这里我们要使用Test的一个java类,它所在的包尾jni.test。

如果加载成功,那么testCls不为0,否则将返回0

 

调用构造函数,创建对象

像我们在java语言中一样,我们首先需要调用构造函数创建一个对象实例,然后再进行方法调用,那么在C++中同样需要我们这么做,当然调用静态方法例外。

testMid = env->GetMethodID( testCls, "<init>", "()V");



Java代码  


if (testMid != 0)  
{
testJobj = env->NewObject(testCls,testMid);
std::cout << "init test class ok" << std::endl;
}


我们可以看到我们首先进行GetMethodID调用,这个函数有三个参数,一个是我们之前获取的jclass对象,第二参数是需要调用的java类中的方法名称,由于我们是调用构造函数,所以<init>是个固定的写法,他就是说明我们要调用构造函数,第三参数是调用方法的参数类型,关于这个参数的类型,我们可以使用javap命令来获取,具体命令如下:

javap -p -s jni.test.Test

然后我们会得到这样的信息

 


Java代码   ​​​​

Compiled from "Test.java"  
public class jni.test.Test extends
public
Signature: ()V
public
Signature: ()Ljava/lang/String;
public
Signature: ()Ljni/test/domain/TestObject;
public void
Signature: ()V
}


 

我们可以看到Test()构造函数,在Signature后面就是该方法的参数类型。

当我们获取构造函数以后,我们就可以对其进行实例化了,使用NewObject

 

方法调用

接下来我们就可以进行方法调用了



Cpp代码   ​​​​


testMid = env->GetMethodID( testCls, "test","()V");  
if
{
env->CallVoidMethod(testJobj,testMid);
}

testMid = env->GetMethodID( testCls, "getMessage","()Ljava/lang/String;");
if
{
jobject msg = env->CallObjectMethod(testJobj,testMid);
std::cout << msg << std::endl;
printf("msg : %d",msg);
}


上面的代码里我们调用两个方法,分别是test和getMessage,我们都是先调用GetmethodID来获取一个jmethodID对象,然后调用CallXXXMethod来进行调用,跟java中的反射调用是一样的。

如果我们需要调用静态方法,我们只需先GetStaticMethodID然后调用CallStaticXXXMethod即可,jni.h中定义了很多Call的方法,比如CallIntMethod,CallBooleanMethod等等,有兴趣可以去查看jni.h

 

下面我们来说一下如何进行回调

我们的java测试类Test中有一个getObject的测试方法,得到了一个java对象,我们拿到该独享后如何进行下一步的调用呢,其实很简单,跟咱们之前的例子是类似的



Cpp代码  

testMid = env->GetMethodID( testCls, "getObject","()Ljni/test/domain/TestObject;");  
if
{
jobject obj = env->CallObjectMethod(testJobj,testMid);
jobject listener = env->NewGlobalRef(obj);
jclass clsj = env->GetObjectClass(listener);
jmethodID func = env->GetMethodID(clsj, "callback", "(Ljava/lang/String;)V");
if(func != NULL)
{
jobject msg1 = env->CallObjectMethod(testJobj,testMid);
env->CallVoidMethod(listener, func, msg1);
}
std::cout << obj << std::endl;
printf("obj : %d",obj);
}

 

同样我们通过GetMethodID获取getObject方法,然后调用该方法,得到一个返回的对象obj,我在代码里进行一下处理,创建了一个全局引用,如果大家只想把他当做局部变量使用,那么不创建全局引用也可以;然后通过GetObjectClass我们得到了jclass对象,接下来就跟我们之前的过程一样了,获取方法,进行调用即可。

上面的代码中我在调用callback方法前有调用了一次getObject方法,主要是测试一下,获取的对象,在进行callback的时候能不能保持其状态。经验证是可以的。

举报

相关推荐

0 条评论