本篇主要介绍一下在jni开发中,C语言如何访问Java的构造函数,父类方法。
1.C语言访问Java构造函数
试想一下这样的场景,当C语言能够访问Java的构造方法时,我们是不是就可以创建一个该类的对象。有了对象那我们就可以随意的调用该类的方法了。是不是很6。
Java代码:
public class JniTest {
//访问Date类的构造函数
public native Date accessConstructor();
//加载动态库
static{
System.loadLibrary("libjnitest");
}
public static void main(String[] args) {
JniTest test=new JniTest();
Date date = test.accessConstructor();
SimpleDateFormat format=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); String formatDate = format.format(date);
System.out.println("当前日期:"+formatDate);
}
}
C代码:
//访问date类的构造函数
JNIEXPORT jobject JNICALL Java_JniExamp_JniTest_accessConstructor
(JNIEnv *env, jobject jobj){
jclass cls=(*env)->FindClass(env,"java/util/Date");
//获取构造方法的id
jmethodID constructor_mid=(*env)->GetMethodID(env,cls,"<init>","()V");
//实例化一个date对象
jobject date_obj= (*env)->NewObject(env,cls,constructor_mid);
//获取getTime的方法ID
jmethodID mid=(*env)->GetMethodID(env,cls,"getTime","()J");
//调用getTime方法
jlong time=(*env)->CallLongMethod(env,date_obj,mid);
printf("currenttime:%ld",time);
return date_obj;
}
输出结果:
代码讲解:
在第二步中获取构造方法id的时候需要传入一个“<init>”,代表获取的是一个构造函数id
第三步实例化一个对象,使用的是
NewObject方法
该方法能获取一个指定构造函数ID的Java对象
我们只是示例了一个访问空参构造函数,如果访问的是带参的构造函数,那么在实例化一个date对象的时候,要把相应参数传递进去。
2.访问父类方法:
为了更好的说明这个示例我们写了一个父类(
Animal
),他有一个方法shout,表明动物叫和这个动作
public class Animal {
public void shout(){
System.out.println("动物各种叫声。。。。。");
}
}
子类
Dog它继承Animal并且重写了父类方法shout()
public class Dog extends Animal{
public void shout() {
System.out.println("小狗汪汪叫。。。。。");
}
}
我们在主函数中这样实现一把:
public class JniTest {
public Animal animal=new Dog();
//访问父类方法
public native void accessParentMethod();
static{
System.loadLibrary("libjnitest");
}
public static void main(String[] args) {
JniTest test=new JniTest();
test.accessParentMethod();
}
}
C代码实现:
//访问父类中的方法
JNIEXPORT void JNICALL Java_JniExamp_JniTest_accessParentMethod
(JNIEnv *env, jobject jobj){
//获取到jclss
jclass cls=(*env)->GetObjectClass(env,jobj);
//获取属性id
jfieldID fid=(*env)->GetFieldID(env,cls,"animal","LJniExamp/Animal;");
//获取属性对象
jobject animal_obj=(*env)->GetObjectField(env,jobj,fid);
//获取Animal类的jclass
jclass animal_cls=(*env)->FindClass(env,"JniExamp/Animal");
//获取animal中的方法ID
jmethodID mid=(*env)->GetMethodID(env,animal_cls,"shout","()V");
//调用了父类中的方法
(*env)->CallNonvirtualObjectMethod(env,animal_obj,animal_cls,mid);
}
运行结果
代码讲解:
这段c代码实现的时候先是获取了一个属性对象
animal,对应的就是 public Animal animal=new Dog();这一段Java代码
获取这个属性id后,根据这个属性id获取到了他的属性对象,animal_obj。对个对象对应的是Dog,所以如果使用这个属性对象调用shout()方法的时候,按照常规调用
CallObjectMethod 执行的结果应该是子类dog中的shout() 小狗汪汪叫。。。。。
但我们需要访问的是小狗的父类Animal ,所以C语言又给我提供了方法CallNonvirtual<type>Method方法可以直接访问父类中的方法。