C语言程序调用java代码

在计算机世界里,有些事是java不能办到的,而没有事是c/c++不能办到的,例如操作硬件设备。所以java调用c/c++是常有的事,而无所不能的c应该不常调用java。但实际情况也不尽然,如android系统(linux系统包装了java界面)里有时会有c程序执行完某功能后要通知java界面。这篇就记录一下c如何调用java。

我这篇的代码基本都是抄的这篇,只是我简化修改了下,算是个笔记吧。

java代码

Person.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Person {
private static String staticInfo = "this is a person";
private String name = "aaa";
public int age = 20;
public static String getStaticInfo() {
return staticInfo;
}
public String getName() {
return "aaa";
}
public int getAge() {
return age;
}
}

我为了追求例子简单写了这样一个不规范的代码,先说说哪里不规范:

  • 声明成员变量的时候直接赋值了;
  • 没写set方法;
  • 没写构造函数;
    这样写出来的java代码平时可能没什么不妥,但是如果通过jni操作它,可能就会出现各种问题,有的问题我这篇最后都不知道怎么解决。所以以后写java代码时一定要规范!

下面记录一个命令,用来查看java类签名:

1
javap -private -s Person

java调用java测试

Main.java

1
2
3
4
5
6
7
8
public class Main {
public static void main(String[] args) {
Person p = new Person();
System.out.println(Person.getStaticInfo());
System.out.println(p.getName());
System.out.println(p.getAge());
}
}

这里的java代码间的调用,确实没感觉出Person.java代码写的有何不妥。

c调用java测试

C调用java的测试代码是这样的:

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jni.h>
int main()
{
printf("c call java test.\n");
JavaVM *jvm = 0;
JNIEnv *env = 0;
JavaVMInitArgs jvm_args;
JavaVMOption opt[1];
opt[0].optionString = "-Djava.class.path=.";
memset(&jvm_args, 0, sizeof(jvm_args));
jvm_args.version = JNI_VERSION_1_6;
jvm_args.nOptions = 1;
jvm_args.options = opt;
long jvm_stat = JNI_CreateJavaVM(&jvm, (void**)&env, &jvm_args);
jclass cls = (*env)->FindClass(env, "Person");
jmethodID static_method = (*env)->GetStaticMethodID(env, cls, "getStaticInfo", "()Ljava/lang/String;");
jstring staticInfo = (jstring)(*env)->CallStaticObjectMethod(env, cls, static_method);
const char *strInfo = (*env)->GetStringUTFChars(env, staticInfo, 0);
printf("%s\n", strInfo);
(*env)->ReleaseStringUTFChars(env, staticInfo, strInfo);
jobject person = (*env)->AllocObject(env, cls);
jmethodID get_name = (*env)->GetMethodID(env, cls, "getName", "()Ljava/lang/String;");
jstring name = (jstring)(*env)->CallObjectMethod(env, person, get_name);
const char *strName = (*env)->GetStringUTFChars(env, name, 0);
printf("%s\n", strName);
(*env)->ReleaseStringUTFChars(env, name, strName);
jfieldID age_field = (*env)->GetFieldID(env, cls, "name", "I");
(*env)->SetIntField(env, person, age_field, 33);
jmethodID get_age = (*env)->GetMethodID(env, cls, "getAge", "()I");
jint age = (*env)->CallIntMethod(env, person, get_age);
printf("%ld\n", age);

return 0;
}

由于我的Person代码写的不正规,导致用c调用的时候有的问题现在也没解决,如上面代码中最后打印的age是0。如果是正规的java代码是好解决的。

makefile

java代码间调用是没必要写makefile的,但是c调用java的代码在编译运行的时候要设好几个地方,还是直接上一个makefile吧。

makefile

1
2
3
4
5
6
7
8
9
JDKHOME = /opt/jdk1.7.0_79
LIBJVM = $(JDKHOME)/jre/lib/amd64/server/libjvm.so
INCS = -I$(JDKHOME)/include -I$(JDKHOME)/include/linux

main:
gcc $(INCS) main.c $(LIBJVM) -Wl,-rpath=$(JDKHOME)/jre/lib/amd64/server
javac *.java
clean:
rm a.out *.o *.class *.log

其他

jni的文章先写到这里吧。以后要深入学习可以看这篇:https://blog.csdn.net/honjane/article/details/53959587