c++对 java代码的调用 方式及环境配置

主要步骤分为以下四个步骤

 1. 通过 jvmdll  获取到 jvm 启动 函数  ,创建jvm   
 2. 通过jvm对象 获取 JNIEnv 类对象     
 3. 通过 jNIEnv 对象 进行获取 函数的 id ,其中需要 javap -s  获取对应的函数签名 
 4. 通过id 进行函数调用 , 对象创建使用 NewObject 方法 , 函数使用CallxxxMethod 对应不同的返回值 

需求环境 : vs2019 , jdk1.8 ;

需要添加的环境变量路径 :
xxx\jdk1.8 \ bin 这是java编译环境所需要的 路径
xxx\jdk1.8\jre \bin // 这是jvm的dll 路径 ,其中需要注意

最后vs 中也需要对 jre文件下的 include 和 lib 进行配置 这样才能引用 jni.h 这个头文件
关于JVM的启动 我封装成了类 , 需要的可以自取

1.h头文件

` CJVMClass 封装的 jvm启动类

#pragma once
#include <string> 
#include <jni.h>
#include <Windows.h> 
class CJVMClass
{
public : 

	CJVMClass(const char * jvmdll = "jvm.dll");
	~CJVMClass();
	
	CJVMClass(const CJVMClass &) = delete;
	CJVMClass & operator=(CJVMClass &) = delete;

	bool isOpen()const ; // 判断jvm 是否打开    
	jclass findClass(const char * name); 

	JavaVM* getJvmObject() const;  
	JNIEnv* getJEnvObject() const;
protected :
	bool initJvm();  
	void destroyJvm(); ;
private :
	std::string m_jvmdll; 


	JNIEnv *m_env = nullptr;;
	JavaVM *m_jvm = nullptr;
	HMODULE m_hjvmdll = nullptr;  

	bool m_isOpenJvm = false;  
};

2 对应的cpp实现

#include "CJVMClass.h"


#include <iostream> 

typedef jint(WINAPI *PFunCreateJavaVM)(JavaVM **, void **, void *);
CJVMClass::CJVMClass(const char * jvmdll)
{
	m_jvmdll = jvmdll;

	
	// 启动虚拟机+
	initJvm();
}

CJVMClass::~CJVMClass()
{
	destroyJvm();
	
}

/*返回 jvm的打开状态 */
bool CJVMClass::isOpen() const
{

	return m_isOpenJvm;
}

jclass CJVMClass::findClass(const char * name)
{
	return m_env->FindClass(name);

}

JavaVM * CJVMClass::getJvmObject() const
{

	return m_jvm;
}

JNIEnv * CJVMClass::getJEnvObject() const
{
	return m_env;
}

bool CJVMClass::initJvm()
{
	JavaVMOption options[2];

	JavaVMInitArgs vm_args;
	options[0].optionString = (char *)("-Xmx256M");
	options[1].optionString = (char *)("-Djava.class.path=.; \\java\\");
	memset(&vm_args, 0, sizeof(vm_args));
	vm_args.version = JNI_VERSION_1_8;
	vm_args.nOptions = 2;
	vm_args.options = options;
	vm_args.ignoreUnrecognized = JNI_TRUE;

	HMODULE hModule = LoadLibrary(L"D:/jdk\\jre\\bin\\server\\jvm.dll");
	if (hModule == NULL)
	{
		std::cerr << " 加载 jvm 失败	 err =  " << GetLastError() << std::endl;
		m_isOpenJvm = false;  
		return	 false;
	}
	
	//取得里面的JNI_CreateJavaVM函数指针  
	PFunCreateJavaVM funCreateJavaVM = (PFunCreateJavaVM)GetProcAddress(hModule, "JNI_CreateJavaVM");

	//调用JNI_CreateJavaVM创建虚拟机  
	jint  res;
	// 启动jvm虚拟机 
	res = funCreateJavaVM(&m_jvm, (void**)&m_env, &vm_args);

	//status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
	if (res < 0 || m_jvm == nullptr || m_env == nullptr)
	{
		if (m_env->ExceptionCheck() == JNI_TRUE)
		{
			m_env->ExceptionDescribe();
			m_env->ExceptionClear();
		}
		FreeLibrary(hModule);
		std::cerr << " 加载 jvm 失败 err =  " << GetLastError() << std::endl;
		return false ;
	}
	m_isOpenJvm = true; 
	return true; 
}

void CJVMClass::destroyJvm()
{ 
	m_isOpenJvm = false; 
	if (m_jvm)
	{
		m_jvm->DestroyJavaVM();
	}
	if (m_hjvmdll)
	{
		FreeLibrary(m_hjvmdll);
		m_hjvmdll = nullptr;
	}
	
}

最后给出一个使用java的测试用例


 class test {
 
    public String name;
    public test(String strr) {
        name = strr ; 
    } 
    public static String sayHello(String name) {
        return "Hello, " + name + "!";
    }
    public static String sayHello(int s) {
        return "Hello, " + s + "!";
    }
    public String sayHello() {
        return "Hello, " + name + "!";
    }

    public String getName() {
        return name;
    }

    public static void main(String[] arg) {    

        System.out.print(sayHello(100) );
    }  
    public void setName(String name) {
        this.name = name;
    }
}

如何调用java的构造函数,使用构建java类对象,并调用成员方法

	CJVMClass jvmcls;
		const char * startClass = "test";
		const char * startMethod = "sayHello";
		cls = jvmcls.getJEnvObject()->FindClass(startClass);
		auto env = jvmcls.getJEnvObject();
			// 调用指定的构造函数, 构造函数的名字叫做<init> ()V 
	    auto mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
	    // 创建 java 类对象 。 
		auto obj = env->NewObject(cls, mid);			
		// 获取属性ID, 然后通过对象obj 修改属性的值  
		auto fid = env->GetFieldID(cls, "name", "Ljava/lang/String;");
		if (fid != 0)
		{
			const char* name = "icejoywoo";
			jstring arg = env->NewStringUTF(name);
			env->SetObjectField(obj, fid, arg); // 修改属性
		}
			// 先获取函数的id ,然后通过对象obj调用成员方法
			mid = env->GetMethodID(cls, startMethod, "()Ljava/lang/String;");
			if (mid != 0)
			{
				jstring result = (jstring)env->CallObjectMethod(obj, mid);
				const char* str = env->GetStringUTFChars(result, 0);
				printf("Result of sayHello: %s\n", str);
				env->ReleaseStringUTFChars(result, 0);
			}

 // 怎么样使用java 静态成员函数 函数 
/* 这里给出了一个调用静态成员 函数的样例 */
			auto mid = (env)->GetStaticMethodID(cls, startMethod, "(I)Ljava/lang/String;");
			if (mid != 0)
			{
				const char* name = "World";
				jstring arg = env->NewStringUTF(name);
				auto  jintarr = env->NewIntArray(1);

				jstring result = (jstring)env->CallStaticObjectMethod(cls, mid, 500);
				const char* str = env->GetStringUTFChars(result, 0);
				printf("Result of sayHello: %s\n", str);
				env->ReleaseStringUTFChars(result, 0);
			}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: SWIG是一个用于连接C/C++和其他编程语言的工具。它提供了一种简单的方式,可以通过自动生成中间代码来实现C/C++的功能与其他编程语言(如Java)之间的交互。 通过SWIG,我们可以将C代码转换为Java代码,并在Java调用C库中的函数。这样做的好处是可以利用C/C++的高性能、底层控制和已有的库文件,并在Java中使用这些功能。 要将C代码转换为Java代码,我们需要这样做的步骤: 1. 创建一个SWIG接口文件,以描述C函数的输入和输出类型。这个接口文件使用SWIG定义的特定语法。 2. 使用SWIG运行器,将接口文件作为输入,并生成一个Java包含C函数的Java接口文件。 3. 创建Java代码,以断开连接的方式调用生成的Java接口文件中的C函数。 SWIG通过将C代码封装在JNI(Java Native Interface)调用中来实现C与Java的交互。这允许Java代码直接调用C代码,并从C代码中返回结果。 使用SWIG进行C到Java转换可以使开发人员更加方便地利用两种语言的优点,提高开发效率和性能。SWIG还支持其他编程语言,如Python、Ruby和Perl,使C代码更容易与这些语言进行交互。 总之,SWIG是一个非常有用的工具,可以帮助在C/C++Java之间实现无缝的交互,为开发人员提供了更多的灵活性和选择,并最大程度地利用现有的代码和库文件。 ### 回答2: Swig是一个开源工具,用于将C/C++代码转换为支持多种编程语言代码,包括Java。使用Swig可以很方便地将C代码转换为Java代码。 转换C代码Java需经过以下步骤: 1. 安装Swig:首先需要安装Swig工具,可以从Swig官方网站下载并按照指示进行安装。 2. 编写接口文件:接口文件是一个后缀名为.i的文件,用于定义需要转换的C代码Java代码的映射关系。在接口文件中,需要指定需要转换的C函数的签名以及导出到Java的类、方法、成员变量等。 3. 生成包装代码:使用Swig生成器来生成C和Java代码的包装代码。通过运行类似以下命令来生成包装代码: ``` swig -java your_interface.i ``` 4. 编译和构建:在生成的C代码中,使用Java Native Interface(JNI)来与Java代码进行交互。使用C/C++编译器将C代码编译为共享库(.so或.dll文件),以供Java程序调用。 5. 构建Java代码:创建Java项目,在项目中引入包装代码并实现调用。可以使用JNI函数调用C函数,或直接使用包装代码生成的Java类和方法进行调用。 需要注意的是,转换C代码Java并不是一种直接的转换过程,可能存在一些依赖问题,对于一些复杂的C代码或使用了C特定功能的代码,还需要在Java代码中添加适当的兼容性处理。 总结而言,Swig是一个强大的工具,可以将C代码转换为Java代码,简化了C/C++Java之间的交互过程,提高了代码的可维护性和可扩展性。 ### 回答3: SWIG(Simplified Wrapper and Interface Generator)是一个用于将C/C++代码转换为其他语言的工具。如果想要将C代码转换为Java代码,可以使用SWIG来完成。 首先,在使用SWIG之前,需要确保已经安装好了SWIG,并且配置好了相关的环境变量。 接下来,需要创建一个包含C代码的接口文件,该文件的后缀名通常为.i。在接口文件中,需要使用SWIG的语法来指定要转换的C函数和类型。 然后,使用SWIG命令对接口文件进行处理,以生成Java代码。命令的语法通常为:swig -java interfacefile.i 完成上述操作后,会生成一系列的Java文件,包括接口文件中指定的函数和类型的Java封装类。 最后,可以将生成的Java代码导入到你的项目中,并与其它Java代码一起进行编译和运行。 需要注意的是,SWIG并非完美的工具,可能会有一些限制和问题。在使用SWIG进行C转Java时,可能会遇到一些类型对应的困难,或者在C和Java之间的内存管理方面的差异。因此,在使用SWIG转换代码时,需要谨慎处理这些问题,并进行相应的修改和调试。 总之,通过使用SWIG,我们可以方便地将C代码转换为Java代码,从而能够在Java平台上使用C语言的功能和库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值