java JNI 的实现(2)-java和C/C++的相互调用.

目录

  概述

  一,java代码

  二,稍微注意通过javah生成的'C/C++'.h头文件和源java代码的关系

  三,在C/C++中实现java的native方法(完整C/C++)

    1,修改age,即Java_juk_demo_JSay_changeAge方法

    2,调用java中的'javaStatic'方法,和上面C/C+实现方法相似

    3,最后测试

概述

  从第一篇java JNI 的实现(1)-又进一步加深对JVM实现的理解对JNI有了大致的理解之后,并知道JNI中java如何调用C/C++等,这篇文章我们进一步将JNI中,java和C/C++的相互调用.

一,java代码:

  我们稍微对类做了更改,如下:

 1 package juk.demo;

 2 

 3 public class JSay {

 4     //member/class field.

 5     public static String country = "cn";

 6     

 7     public int age = 20;

 8     

 9     //native method.

10     public native void changeAge();

11     

12     public static native void staticSay();

13     

14     //member method.

15     public void getVoid() {

16         

17     }

18     

19     public String getString() {

20         return "json";

21     }

22 

23     public int getInt() {

24         return 1;

25     }

26     

27     private void getUnknown() {

28         

29     }

30     

31     public int[] getIntArray() {

32         return new int[]{1,2};

33     }

34     

35     //static method.

36     public static void javaStatic() {

37          System.out.println(country + ", center china");;

38     }

39     

40     static {

41         System.loadLibrary("JNITestCCPP");

42     }

43         

44 

45     public static void main(String[] args) {

46         //invoke native method.

47         JSay.staticSay();

48         

49         JSay jSay = new JSay();

50         System.out.println("before invoke native,age=" + jSay.age);

51         jSay.changeAge();

52         System.out.println("after invoke native,age=" + jSay.age);

53         

54     }

55 

56 }
View Code

  这次,java代码有两个native方法(changeAge和staticSay),并且有许多成员和类的普通java方法(主要是研究通过javah产生的.h头文件和源java代码直接的关系),

  我们这次的目的,一是在java中调用'changeAge' native方法的时候,在C/C++代码中对其对象的age属性进行更改(当然,一般成员变量都是封装的,这里只是为了测试);二是在java调用'staticSay' native方法的时候,在C/C++代码中,反过来调用java的'javaStatic'方法.

二,稍微注意通过javah生成的'C/C++'.h头文件和源java代码的关系:

 1 /* DO NOT EDIT THIS FILE - it is machine generated */

 2 #include "jni.h"

 3 /* Header for class juk_demo_JSay */

 4 

 5 #ifndef _Included_juk_demo_JSay

 6 #define _Included_juk_demo_JSay

 7 #ifdef __cplusplus

 8 extern "C" {

 9 #endif

10 /*

11  * Class:     juk_demo_JSay

12  * Method:    changeAge

13  * Signature: ()V

14  */

15 JNIEXPORT void JNICALL Java_juk_demo_JSay_changeAge

16   (JNIEnv *, jobject);

17 

18 /*

19  * Class:     juk_demo_JSay

20  * Method:    staticSay

21  * Signature: ()V

22  */

23 JNIEXPORT void JNICALL Java_juk_demo_JSay_staticSay

24   (JNIEnv *, jclass);

25 

26 #ifdef __cplusplus

27 }

28 #endif

29 #endif
View Code

  我们发现,通过javah命令生成的C/C++.h头文件,不会在.h头文件中出现(这其实也是很合情理的,但是我们却可以通过java中的native方法对应的.h中的方法的参数'JNIEnv *'去获得java中所有的成员).

  三,在C/C++中实现java的native方法(完整C/C++):

 1 #include <iostream>

 2 #include "juk_demo_JSay.h"

 3 using namespace std;

 4 

 5 //3 ways to get jclass:

 6 /*

 7 1,(JNIEnv *)->FindClass(class-name),which find the class by the classpath.

 8 2,(JNIEnv *)->GetObjectClass(jobject).

 9 3,(JNIEnv *)->GetSuperclass(jobject).

10 */

11 

12 /*

13  * Class:     juk_demo_JSay

14  * Method:    changeAge

15  * Signature: ()V

16  */

17 JNIEXPORT void JNICALL Java_juk_demo_JSay_changeAge

18   (JNIEnv *env, jobject obj) {

19     jclass JSayClass = env->GetObjectClass(obj);

20     jfieldID ageId = env->GetFieldID(JSayClass, "age", "I");

21     //env->GetIntField(obj, ageId);

22     env->SetIntField(obj, ageId, 22);    //set the age with a new value.

23 }

24 

25 /*

26  * Class:     juk_demo_JSay

27  * Method:    staticSay

28  * Signature: ()V

29  */

30 JNIEXPORT void JNICALL Java_juk_demo_JSay_staticSay

31   (JNIEnv *env, jclass clz) {

32     //jclass JSayClass = env->FindClass("juk.demo.JSay");

33 

34     //javaStatic method.

35     //the third argument,can be fetch with 'javap' command.

36     jmethodID getStaticMethodId = env->GetStaticMethodID(clz, "javaStatic", "()V");

37     env->CallStaticVoidMethod(clz, getStaticMethodId, NULL);

38 

39     //get age field.

40     /*jfieldID countryId = env->GetStaticFieldID(JSayClass, "country", "Ljava/lang/String;");

41     env->GetStaticObjectField(JSayClass, countryId);*/

42 }
View Code

    1,修改age,即Java_juk_demo_JSay_changeAge方法,我们首先要获得jclass对象(jclass对应于java中的Class对象),而jclass对象的获得可以根据3中方式:

1,(JNIEnv *)->FindClass(class-name),which find the class by the classpath.

2,(JNIEnv *)->GetObjectClass(jobject).

3,(JNIEnv *)->GetSuperclass(jobject).

然后可以通过(JNIEnv *)获得属性的ID,并修改.稍微注意的是'env->GetFieldID'方法中的第3个参数,是为了区别方法的重载问题,

如下表(来自oracle的Chapter 3: JNI Types and Data Structures)

Java VM Type Signatures
Type Signature Java Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type

sun为了方便我们程序员,写一个工具(即,jdk中的javap),而不用我们记忆那些类型签名,例如,我们可以在包含该java的class的目录上(通过命令行),输入 'javap -s -public juk.demo.JSay',即可得到对应的签名,如:

 1 Compiled from "JSay.java"

 2 public class juk.demo.JSay extends java.lang.Object{

 3 public static java.lang.String country;

 4   Signature: Ljava/lang/String;

 5 public int age;

 6   Signature: I

 7 public juk.demo.JSay();

 8   Signature: ()V

 9 public native void changeAge();

10   Signature: ()V

11 public static native void staticSay();

12   Signature: ()V

13 public void getVoid();

14   Signature: ()V

15 public java.lang.String getString();

16   Signature: ()Ljava/lang/String;

17 public int getInt();

18   Signature: ()I

19 public int[] getIntArray();

20   Signature: ()[I

21 public static void javaStatic();

22   Signature: ()V

23 public static void main(java.lang.String[]);

24   Signature: ([Ljava/lang/String;)V

25 }
View Code

    2,调用java中的'javaStatic'方法,和上面C/C+实现方法相似,不过由于在java源码中,native被定义成了类方法,所以不用获得jclass,而直接从参数获取.同理,通过(JNIEnv *)获得java中的javaStatic方法,并调用.

    最后,我们再java主函数中进行测试,结果为:

cn, center china

before invoke native,age=20

after invoke native,age=22

 

你可能感兴趣的:(c/c++)