语言混编之c调用java
经过验证可以实现,先将实现代码贴出,以备以后使用。
本文默认你的java开发环境已经安装成功,并且对于java语言和c++语言有过了解。
编写测试用类:Demo.java
代码如下:
public class Demo
{
public static int COUNT = 8;
private String msg;
private int[] counts;
public Demo ()
{
this ("default constructor");
}
public Demo (String msg)
{
this.msg = msg;
this.counts = null;
}
public String getMessage ()
{
return msg;
}
public static String getHelloWorld ()
{
return "hello world!";
}
public String append (String str, int i)
{
return str + i;
}
public int[] getCounts ()
{
return counts;
}
public void setCounts (int[] counts)
{
this.counts = counts;
}
public void throwExcp () throws IllegalAccessException
{
throw new IllegalAccessException ("exception occurs");
}
}
由于在java中能够使用函数重载,所以在c语言中调用java是需要确定究竟是调用的是那个函数。在jdk中提供了javap程序。
Javap将一个类和它的方法的一些转储信息输出到标准输出。该工具不把代码反编译为java源代码,但是它会把字节代码反汇编成为由Java虚拟机规范定义的字节代码指令。其用法如下:
-l 输出本地变量表
-public 输出公用类名和方法名
-protected 输出类的受保护方法
-private 输出类的似有方法
-verbose 输出类的栈的信息和本地方法的个数
回到原来主题:
javap -s -p Demo
无法上传图片^_^想象一下吧。在输出中找到如下的语句:
public java.lang.String append(java.lang.String, int);
Signature: (Ljava/lang/String;I)Ljava/lang/String;
在vs2008中新建一个工程(win32 console application),配置工程属性:将jdk中include目录下的头文件加入到工程中,并将该文夹下的win32子目录下的header file同样加入到工程中。
新建main.cpp
代码如下:
#include <Windows.h>
#include "jni.h"
#include <string>
#include <iostream>
using namespace std;
jstring NewJString (JNIEnv* env, LPCTSTR str);
string JStringToCString (JNIEnv *env, jstring str);
int main ()
{
typedef jint (WINAPI* PFunCreateJavaVM) (JavaVM**, void**, void*);
int res;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
JavaVM* jvm;
JNIEnv* env;
options[0].optionString = options[0].optionString = "-Djava.compiler=NONE";
//classpath should be set to find the .class file in the following
//here we put the class file in the directory c:\ Demo.class
options[1].optionString = "-Djava.class.path=.;C:\\";
options[2].optionString = "-verbose:NONE";
vm_args.version = JNI_VERSION_1_4;
vm_args.nOptions = 3;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
//load the dll
HINSTANCE hInstance = ::LoadLibrary("C:\\Program Files\\Java\\jdk1.6.0_10\\jre\\bin\\client\\jvm.dll");
if (hInstance == NULL)
return 1;
PFunCreateJavaVM funCreateJavaVM = (PFunCreateJavaVM)::GetProcAddress(hInstance, "JNI_CreateJavaVM");
res = (*funCreateJavaVM)(&jvm, (void**)&env, &vm_args);
if (res < 0)
{
return -1;
}
jclass cls = env->FindClass("Demo");
jobject obj = env->AllocObject(cls);
jmethodID mid = env->GetMethodID(cls, "append","(Ljava/lang/String;I)Ljava/lang/String;");
const char szTest[] = "HELLO WORLD";
jstring arg = NewJString(env, szTest);
jstring msg = (jstring) env->CallObjectMethod(obj, mid, arg, 12);
cout << JStringToCString(env, msg);
jvm->DestroyJavaVM();
::FreeLibrary(hInstance);
return 0;
}
string JStringToCString (JNIEnv *env, jstring str)// (jstring str, LPTSTR desc, int desc_len)
{
if(str==NULL)
{
return "";
}
int len = env->GetStringLength(str);
wchar_t *w_buffer = new wchar_t[len+1];
//char* w_buffer = new char [len + 1];
char *c_buffer = new char[2*len+1];
ZeroMemory(w_buffer,(len+1)*sizeof(wchar_t));
const jchar * jcharString = env->GetStringChars(str, 0);
wcscpy(w_buffer,(wchar_t*)jcharString);
env->ReleaseStringChars(str,jcharString);
ZeroMemory(c_buffer,(2*len+1)*sizeof(char));
len = WideCharToMultiByte(CP_ACP, 0, w_buffer, len, c_buffer, 2 * len, NULL, NULL);
string cstr = c_buffer;
delete[] w_buffer;
delete[] c_buffer;
return cstr;
}
jstring NewJString(JNIEnv *env, LPCTSTR str)
{
if(!env || !str)
{
return 0;
}
int slen = strlen(str);
jchar* buffer = new jchar[slen];
int len = MultiByteToWideChar(CP_ACP,0,str,strlen(str), (LPWSTR)buffer,slen);
if(len>0 && len < slen)
{
buffer[len]=0;
}
jstring js = env->NewString(buffer,len);
delete [] buffer;
return js;
}
注意上面的路径的使用需要根据本地的文件路径来设置。编译运行即可。
作者:许强1. 本博客中的文章均是个人在学习和项目开发中总结。其中难免存在不足之处 ,欢迎留言指正。 2. 本文版权归作者和博客园共有,转载时,请保留本文链接。