需要注意的是jclass对象class_Employee会随着本次native方法的结束而被回收,因此不能直接保留该变量到某全局变量或类的成员变量,以便下次再调用时不用再获取该对象。如果没有特殊的处理,在每次进入native的开始部分均需要调用env->GetObjectclass()JNI方法获取该变量。如果确实希望避免这种重复的调用,可使用下面的技巧予以规避:
1 static jclass class_X = 0;
2 static jfieldID id_a;
3 ...
4 if (class_X == 0) {
5 jclass cx = env->GetObjectClass(obj);
6 class_X = env->NewGlobalRef(cx);
7 id_a = env->GetFieldID(env,cls,\"a\",\"...\");
8 }
然而需要注意的是,在结束对类的使用时,务必调用:env->DeleteGlobalRef(class_X)来通知JVM释放该资源。
3) 含有main函数的调用测试代码:
1 public class MyTest {
2 public static void main(String[] args) throws Exception {
3 Employee[] staff = new Employee[3];
4 staff[0] = new Employee(\"Harry Hacker\",35000);
5 staff[1] = new Employee(\"Carl Cracker\",75000);
6 staff[2] = new Employee(\"Tony Tester\",38000);
7 for (Employee e : staff)
8 e.raiseSalary(5);
9 for (Employee e : staff)
10 e.print();
11 }
12 }
13 /* 输出结果如下:
14 Harry Hacker 71750.0
15 Carl Cracker 153750.0
16 Tony Tester 77900.0
17 */
7. 编码签名:
为了访问实例域和调用Java编程语言中定义的方法,你必须学习\"编入\"数据类型的名称和方法签名的规则,见如下编码方案:
B byte
C char
D double //如下例中env->GetFieldID(class_Employee,\"salary\",\"D\");
F float
I int
J long
S short
V void
Z boolean
Lclassname; 类的类型
如果描述数组类型,需要使用[,如果二维数组[[,以此类推。如:
[Ljava/lang/String; //String一维数组
[[F //float[][]二维数组
要建立一个方法的完整签名,需要把括号内的参数类型都列出来,然后列出返回值类型,如:
(II)I //一个接收两个整型参数并返回一个整数的方法编码。
上例中的print方法的签名是:(Ljava/lang/String;)V //表示该方法接收一个字符串String参数,返回值为void。
注意,在L表达式结尾处的分号是类型表达式的终止符,而不是参数之间的分隔符,如上例中Employee的构造函数: