主要步骤分为以下四个步骤
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);
}