C++调用JAVA(Win10)

1、写一个Java类,生成.class文件

①java源码

package com;
public class demo {
    public demo(){   //Constructor
        super();
    }
    public static int add(int a,int b){  
        return a+b;
    }
    public boolean judge(boolean bool){
        return !bool;
    }    
}
②包名是com,切换到文件目录(javac  demo.java),生成字节码文件
③小插曲:编译一直出错,代码没有问题,我用的notepad++打开的,编码问题(修改为utf-8无BOM格式编码)

④现在com文件下有两个文件(一个java文件,一个class文件)

2、用VS2013写C++代码

①加载jni.h头文件

属性-->配置属性--->VC++目录--->包含目录----》(D:\java\jdk\include)

这里注意:include文件夹下有子文件夹,把子文件夹中的头文件都拷贝一份放在最外层

②源码(中间有一个地方需要修改,自己的jvm.dll文件路径,VS建立的工程是空项目,源文件也是自己新建)

#include<windows.h>
#include <jni.h> 
#include<iostream>
using namespace std;
int main()
{
	JavaVMOption options[1];
	JNIEnv *env;
	JavaVM *jvm;
	JavaVMInitArgs vm_args;
	long status;
	jclass cls;
	jmethodID mid;
	jint square;
	jboolean not;
	jobject jobj;
	cout << "begin" << endl;
	options[0].optionString = "-Djava.class.path=.";
	vm_args.version = JNI_VERSION_1_6;
	vm_args.nOptions = 1;
	vm_args.options = options;
	vm_args.ignoreUnrecognized = JNI_TRUE;
	typedef jint(WINAPI *PFunCreateJavaVM)(JavaVM **, void **, void *);
	const  char  szJvmPath[] = "D://java//jdk//jre//bin//server//jvm.dll";
	HINSTANCE hInstance = ::LoadLibrary(szJvmPath);
	if (hInstance == NULL)
	{
		cout << "加载链接库失败" << endl;
		cout << ::GetLastError() << endl;
		cout << hInstance << endl;
		int x;cin >> x;          //让程序暂停
		return -2;
	}
	//取得里面的JNI_CreateJavaVM函数指针   
	PFunCreateJavaVM funCreateJavaVM = (PFunCreateJavaVM)::GetProcAddress(hInstance, "JNI_CreateJavaVM");
	status = (*funCreateJavaVM)(&jvm, (void**)&env, &vm_args);
	if (status != JNI_ERR) {
		cout << "JVM虚拟机创建成功" << endl;
		cls = env->FindClass("com/demo");
		if (cls != 0) {
			cout << "自定义类加载成功" << endl;
			mid = env->GetStaticMethodID(cls, "add", "(II)I");
			if (mid != 0) {
				square = env->CallStaticIntMethod(cls, mid, 5, 5);
				std::cout << "ans=" << square << std::endl;
			}
			mid = env->GetMethodID(cls, "<init>", "()V");
			if (mid != 0) {
				jobj = env->NewObject(cls, mid);
				std::cout << "init ok" << std::endl;
			}
			mid = env->GetMethodID(cls, "judge", "(Z)Z");
			if (mid != 0) {
				not = env->CallBooleanMethod(jobj, mid, 1);
				if (!not) {
					std::cout << "Boolean ok" << std::endl;
				}
			}
		}
		jvm->DestroyJavaVM();
	}
	else
		return -1;
	cout << "end" << endl;
	int x;cin >> x;     //让程序暂停
}
③竟然出错了(修改编码方式)

修改编码方式:属性-->配置--->常规--->字符集(改成多字符集)

链接库加载失败

平台不兼容的问题,VS默认是win32,修改成X64即可。运行会报错找不到一个dll文件

解决:属性-->配置-->链接器--->输入---->附加依赖项(不要从父级继承,取消复选框)

⑤链接库加载成功了,虚拟机也创建成功了,但是加载自定义类出错了(默认路径是环境变量下的,用点代替,可以导入java/lang,要想导入自定义类需要修改路径)

修改加载类的路径:(该路径为.class所在的路径,路径下有com文件夹,文件夹下有.class文件)

options[0].optionString = "-Djava.class.path=C://Users//HQH//Desktop//C++调用Java";
⑤运行成功,注意源码中的传参和参数获取(II)I表示两个int类型输入返回类型int(以及区别不同的返回类型调用函数不一致)


3、如果传参和返回值都是String类型怎么办?

①C++/java和jni的数据类型不一致,需要类型转换

//传参,字符串转换jstring
jstring stringTojni(JNIEnv* env, const char* pat)
{
	jclass strClass = env->FindClass("Ljava/lang/String;");
	jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
	jbyteArray bytes = env->NewByteArray(strlen(pat));
	env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
	jstring encoding = env->NewStringUTF("utf-8");
	jstring rstStr = (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
	return rstStr;
}
//接收返回值,jstring转换成字符串
char* jniTostring(JNIEnv* env, jstring jstr)
{
	char* rtn = NULL;
	jclass clsstring = env->FindClass("java/lang/String");
	jstring strencode = env->NewStringUTF("utf-8");
	jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
	jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
	jsize alen = env->GetArrayLength(barr);
	jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
	if (alen > 0)
	{
		rtn = (char*)malloc(alen + 1);
		memcpy(rtn, ba, alen);
		rtn[alen] = 0;
	}
	env->ReleaseByteArrayElements(barr, ba, 0);
	return rtn;
}
②调用(现在知道"-Djava.class.path=."路径的用处了吧,就是jdk路径中的一些包)

//调用
if (cls != 0) {
	cout << "自定义类加载成功" << endl;
	mid = env->GetStaticMethodID(cls, "fun", "(Ljava/lang/String;)Ljava/lang/String;");   //(传参类型)返回值类型
	if (mid != 0) {
		string s = "C:\\Users\\HQH\\Desktop\\1.jpg";
		jstring a = (jstring)env->CallObjectMethod(cls, mid, stringTojni(env, s.c_str()));    //string转换char
		cout << a << endl;
		char * aa = jniTostring(env, a);
		cout << aa << endl;
		cin >> x;          //让程序暂停
	}
}

4、普通java代码可以,那么java程序中若调用第三方jar包怎么办?(多添加一个包的路径即可)

options[0].optionString = "-Djava.class.path=自定义类路径;C://Users//HQH//Desktop//aiyouwei//demo//bin//com//libtensorflow-1.6.0.jar";
5、我是利用C++调java,java中使用了TensorFlow的Jar包。那么java环境如何配置TensorFlow接口

①引入刚刚的jar包

②项目右键:Build Path--->Configure--->Libraries--->JRE System--->Native libary location(添加dll文件所在的文件夹 tensorflow_jni.dll)


6、不报错,但是程序没有预期结果,怎么办?

解决办法:把相关的dll全部copy到c++工程项目下(上一步加载的dll文件)

总结:

①C++调用java,需要用到jni,数据类型转换

②C++调用java,-Djava.class.path的配置

③java中路径最好不要设置成相对路径,在被调用时,相对路径是在C++项目下的。若想用需要把用到的文件copy到C++目录下。

猜你喜欢

转载自blog.csdn.net/hqh131360239/article/details/79875502
今日推荐