C++ 跨语言调用 Java

C++ 跨语言调用 Java  

  Java JDK 提供了 JNI 接口供 C/C++ 程序调用 Java 编译后的类与方法,主要依赖于头文件(jni.h) 和 动态库(jvm.so/jvm.dll),由于 JNI 包含了丰富的接口映射和跨语言的数据通信,非常复杂(坑 深不见底),所以这里只对一个测试程序进行简单的描述。

  最开始测试的时候选择了 Window7 64 的环境,安装的 Java JDK 也是64位的,但是我们都知道 VS 编译的程序默认情况下都是32位程序,所以我在 LoadLibrary(“jvm.dll”)的时候总是失败,所以就放弃了 Windows 环境下的测试(懒得去编译64的程序),最终我使用了 CentOS7 64 完成了测试,并且测试的 Java 版本是 1.7(系统自带openjdk)。

测试的 Java 代码如下所示。

1 public class MyTest {
2     private static int magic_counter = 777;
3
4     public static void callback() {
5     System.out.println("Hello world in java from cplusplus");
6     System.out.print("Magic number: ");
7     System.out.println(magic_counter);
8     }
9 }

  编写完 Java 测试程序之后,使用命令:javac MyTest.java 对 Java 类进行编译,并生成相应的 MyTest.class 文件,这个文件所在的位置非常重要,这关系到我们的 C++ JNI 程序能否找到这个文件,因为我们在 C++ JNI 程序中指定了 "-Djava.class.path=." 就是C++程序运行的当前目录,所有这里我们需要把 MyTest.class 文件拷贝到 C++ 程序的运行目录中。

  此外由于 JNI 函数需要将调用对象的 Signature ID 传入,所以我们还需要知道你所有使用对象的 Signature。通过命令: javap -s -p MyTest.class 命令可以获取后所有函数与变量的 Signature。如下图所示。

  在编译程序之前,需要了解你机器上的 Java 版本,及 jni.h 和 jvm.so 所在的位置,方便程序编译时能够找到相应的 Java 依赖,这里我使用了 CMake 来辅助编译,相应的 CMakeList.txt 如下所示。

cmake_minimum_required(VERSION 3.5)
project(testjni)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

include_directories(
        #/opt/program/jdk1.8.0_121/include/linux
        #/opt/program/jdk1.8.0_121/include
        /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.111-2.6.7.2.el7_2.x86_64/include/linux
        /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.111-2.6.7.2.el7_2.x86_64/include

)
link_directories(
        #/opt/program/jdk1.8.0_121/jre/lib/amd64/server
        /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.111-2.6.7.2.el7_2.x86_64/jre/lib/amd64/server/
)

set(SOURCE_FILES main.cpp)
add_executable(testjni ${SOURCE_FILES})

target_link_libraries(
        testjni
        jvm
        )

  下面是 C++ JNI 程序的简单示例,如下所示。

#include <iostream>
#include <jni.h>
#include <memory.h>

int main()
{
    char opt1[] = "-Djava.compiler=NONE"; /** 暂时不知道啥意思,网上抄来的 */
    char opt2[] = "-Djava.class.path=.";  /** 指定Java类编译后.class文件所在的目录 */
    char opt3[] = "-verbose:NONE";        /** 暂时不知道啥意思,网上抄来的 */

    JavaVMOption options[3];
    options[0].optionString = opt1; options[0].extraInfo = NULL;
    options[1].optionString = opt2; options[1].extraInfo = NULL;
    options[2].optionString = opt3; options[2].extraInfo = NULL;

    JavaVMInitArgs jargv;
    jargv.version = JNI_VERSION_1_6; /** JDK JNI VERSION*/
    jargv.nOptions = 3;
    jargv.options = options;
    jargv.ignoreUnrecognized = JNI_TRUE;

    JavaVM* jvm = NULL;
    JNIEnv* jenv = NULL;
    jint res = JNI_CreateJavaVM( &jvm, (void**)&jenv, &jargv );
    if ( 0 != res )
        return 1;

    jclass jc = jenv->FindClass( "MyTest" );
    if ( NULL == jc )
        return 1;

    jmethodID jmid = jenv->GetStaticMethodID( jc, "callback", "()V" );
    if ( NULL == jmid )
        return 1;

    jenv->CallStaticVoidMethod( jc, jmid );

    /** 在网上没有找到任何关于空间相关 JavaVM 和 JNIEnv 资源释放的描述 */
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

  最终输出的结果与预期的一致,就到这里,在这么深的坑里,祝大家好运哦。

时间: 2024-11-05 06:03:16

C++ 跨语言调用 Java的相关文章

Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用

目录: 一.什么是Thrift? 1) Thrift内部框架一瞥 2) 支持的数据传输格式.数据传输方式和服务模型 3) Thrift IDL 二.Thrift的官方网站在哪里? 三.在哪里下载?需要哪些组件的支持? 四.如何安装? 五.Golang.Java.Python.PHP之间通过Thrift实现跨语言调用 1) Golang 客户端和服务端的实现及交互 2) python 客户端的实现与golang 服务端的交互 3) php 客户端的实现与golang 服务端的交互 4) java

(转)使用Thrift0.9.1实现跨语言调用Golang、Php、Python、Java

问题导读:什么是Thrift?Thrift的官方网站在哪里?Golang.Java.Python.PHP之间如何通过Thrift实现跨语言调用? 一.什么是Thrift Thrift是一种可伸缩的跨语言服务的发展软件框架.它结合了功能强大的软件堆栈的代码生成引擎,以建设服务. Thrift是facebook开发的,07年4月开放源代码,08年5月进入apache孵化器.创造Thrift是为了解决facebook系统中各系统间大数据量的传 输通信以及系统之间语言环境不同需要跨平台的特性.所以thr

Java跨语言调用,使用JNA访问Java外部接口

1. JNA简单介绍 先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即可.首先看下JNI调用C/C++的过程,注意写程序时自下而上,调用时自上而下. 可 见步骤非常的多,很麻烦,使用JNI调用.dll/.so共享库都能体会到这个痛苦的过程.如果已有一个编译好的.dll/.so文件,如果使用JNI技 术调用,我们首先需要使用C语言另外写一个.dll/.so共享库,使用S

C#写的dll跨语言调用

C#写的dll为非标准的windows下dll,故 一般其他语言不能直接调用,当然基于.net平台下的编程语言是可以调用,要让其他语言调用C#写的dll一般通过webservice服务或者是Com 方式.经过在网上找资料以及自身的实践发现可以通过以下方式在Delphi和VB语言中调用. 1.编写C#写dll,用VS新建一个类库项目TestDll,源码如下: using System; using System.Collections.Generic;using System.Text;using

CLS(公共语言规范)的CLSCompliant(跨语言调用)

.net的一个很重要的特性就是跨语言的编程,用C#写的dll可以在VB.net里调用,例如:用C#写的一个类,编译到dll中,然后在VB.net中调用: using System;namespace CLSsample{ public class CLSTest {  public CLSTest()  {     }  public void ABC()  {   Console.WriteLine("ABC");  } }} 在VB.net中调用:Dim c As CLSsampl

03_Android NDK中C语言调用Java代码,javah的使用,javap的使用以及生成签名,Android.mk的编写,C代码的编写

?? 1  案例场景,通过C语言回调Java的代码,案例的最终界面: 2  案例的代码结构如下: 3 编写DataProvider的代码: package com.example.ndkcallback; public class DataProvider { //C调用java空方法 public void helloFromJava(){ System.out.println("哈哈哈  我被调用了"); } //C调用java中的带两个int参数的方法 public int Ad

IDispatch接口 - 跨语言调用

当一个COM接口支持IDispatch的时候(Dual接口),它就可以被其他语言调用. 这里我用perl试了一下. perl测试代码 use warnings; use strict; use Win32::OLE; use constant ADS_UF_ACCOUNTDISABLE => 2; use constant ADS_SCOPE_SUBTREE => 2; my $MyCom = Win32::OLE->new( "MyCom.MyCar" ) or d

Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结

1.1. 边缘检测的基本方法Canny最常用了1 1.2. 编写matlab边缘检测代码,保存为m文件1 1.3. 通过cli接口调用Matlab执行m文件1 1.4. 效果如图1 1.1. 边缘检测的基本方法Canny最常用了 1.2. 编写matlab边缘检测代码,保存为m文件 fprintf('Hello World'); imag = imread('C:\00edge\a.jpg');  %读取 imag = rgb2gray(imag);        %转化为灰度图 %imag_f

Android学习JNI,使用C调用JAVA语言

本节学习使用C语言调用JAVA语言.在生活中比如我们某些底层的硬件必须使用C语言去编写,当C语言返回的某些数值显示在界面上时,就比如使用JNI.这样可以将C返回的值显示在界面上. 本节模拟传感器返回的值,通过进度条显示灵敏度,然后显示到界面上. 1:界面布局就补多说了.里面就2个Button,一个用于开启监控,一个用于关闭监控,一个进度条 2:Activity代码如下: //开始监控button public void start(View v) { startMonitor(); } //停止