CPlusPlus - #028 跨语言桥接技术:在 Java 中调用 C++ 函数

跨语言桥接技术:在 Java 中调用 C++ 函数

1 前言

在现代软件开发中,跨语言桥接技术成为了实现不同编程语言之间互操作的重要手段。尤其是在需要将高性能的 C++ 代码与易于开发的 Java 应用程序结合时,这种技术显得尤为重要。通过这种桥接技术,开发者可以充分利用 C++ 的性能优势,同时又能够借助 Java 的丰富生态系统和开发便利性。本文将探讨如何在 Java 中调用 C++ 函数,通过详细的示例代码演示跨语言桥接的实现过程,包括如何定义和调用 C++ 函数、如何处理数据类型的映射以及如何管理 C++ 对象的生命周期。希望通过这篇文章,读者能够掌握在 Java 应用中有效地集成 C++ 代码的方法,进而提升其开发效率和应用性能。

2 示例代码

2.1 myapi.h

#pragma once

#ifdef MYAPI_EXPORTS
#define MYAPI __declspec(dllexport) // 导出符号
#else
#define MYAPI __declspec(dllimport) // 导入符号
#endif

#include "jni.h"

#ifdef __cplusplus
extern "C" {
#endif
    // 结构体类型定义,表示一个包含 x 和 y 两个整数的结构体
    typedef struct {
        int x;
        int y;
    } MyStruct;
    // 普通 C++ 函数声明
    MYAPI int AddNumbers(int a, int b);
    MYAPI double AddDoubles(double a, double b);
    MYAPI void AddDoublesByRef(double* a, double* b, double* result);
    MYAPI char GetCharValue(char c);
    MYAPI void PrintString(const char* str);
    MYAPI const char* GetChineseString();
    MYAPI MyStruct AddStructs(MyStruct a, MyStruct b);




    // 类定义,表示一个包含整数值的类
    class MyClass {
    public:
        int value; // 类的成员变量,表示一个整数值

        // 构造函数,初始化 value
        MyClass(int v) : value(v) {}

        // 成员函数,返回 value 的值
        int GetValue() const { return value; }
    };

    // JNI 入口点函数声明
    JNIEXPORT jint JNICALL Java_MyNative_addNumbers(JNIEnv* env, jobject obj, jint a, jint b);
    JNIEXPORT jdouble JNICALL Java_MyNative_addDoubles(JNIEnv* env, jobject obj, jdouble a, jdouble b);
    JNIEXPORT void JNICALL Java_MyNative_addDoublesByRef(JNIEnv* env, jobject obj, jdoubleArray a, jdoubleArray b, jdoubleArray result);
    JNIEXPORT jchar JNICALL Java_MyNative_getCharValue(JNIEnv* env, jobject obj, jchar c);
    JNIEXPORT void JNICALL Java_MyNative_printString(JNIEnv* env, jobject obj, jstring str);
    JNIEXPORT jstring JNICALL Java_MyNative_getChineseString(JNIEnv* env, jobject obj);
    JNIEXPORT void JNICALL Java_MyNative_freeString(JNIEnv* env, jobject obj, jstring str);
    JNIEXPORT jobject JNICALL Java_MyNative_addStructs(JNIEnv* env, jobject obj, jobject structA, jobject structB);

    // JNI 对象操作函数声明
    JNIEXPORT jlong JNICALL Java_MyNative_createMyClass(JNIEnv* env, jclass cls, jint value);
    JNIEXPORT void JNICALL Java_MyNative_destroyMyClass(JNIEnv* env, jclass cls, jlong objPtr);
    JNIEXPORT jint JNICALL Java_MyNative_getMyClassValue(JNIEnv* env, jclass cls, jlong objPtr);


#ifdef __cplusplus
}
#endif

2.2 myapi.cpp

#include "myapi.h"
#include <iostream>
#include <cstring>
#include <jni.h>

// 普通 C++ 函数实现
MYAPI int AddNumbers(int a, int b) {
    return a + b;
}

MYAPI double AddDoubles(double a, double b) {
    return a + b;
}

MYAPI void AddDoublesByRef(double* a, double* b, double* result) {
    *result = *a + *b;
}

MYAPI char GetCharValue(char c) {
    return c;
}

MYAPI void PrintString(const char* str) {
    std::cout << str << std::endl;
}

MYAPI const char* GetChineseString() {
    const char* str = u8"你好,世界!";
    size_t len = strlen(str) + 1;
    char* result = new char[len];
    strcpy_s(result, len, str);
    return result;
}

MYAPI void FreeString(const char* str) {
    delete[] str;
}

MYAPI MyStruct AddStructs(MyStruct a, MyStruct b) {
    MyStruct result;
    result.x = a.x + b.x;
    result.y = a.y + b.y;
    return result;
}

// JNI 入口点函数实现
JNIEXPORT jint JNICALL Java_MyNative_addNumbers(JNIEnv* env, jobject obj, jint a, jint b) {
    return AddNumbers(a, b);
}

JNIEXPORT jdouble JNICALL Java_MyNative_addDoubles(JNIEnv* env, jobject obj, jdouble a, jdouble b) {
    return AddDoubles(a, b);
}

JNIEXPORT void JNICALL Java_MyNative_addDoublesByRef(JNIEnv* env, jobject obj, jdoubleArray a, jdoubleArray b, jdoubleArray result) {
    jdouble* aElements = env->GetDoubleArrayElements(a, NULL);
    jdouble* bElements = env->GetDoubleArrayElements(b, NULL);
    jdouble* resultElements = env->GetDoubleArrayElements(result, NULL);

    AddDoublesByRef(aElements, bElements, resultElements);

    env->ReleaseDoubleArrayElements(a, aElements, 0);
    env->ReleaseDoubleArrayElements(b, bElements, 0);
    env->ReleaseDoubleArrayElements(result, resultElements, 0);
}

JNIEXPORT jchar JNICALL Java_MyNative_getCharValue(JNIEnv* env, jobject obj, jchar c) {
    return GetCharValue(c);
}

JNIEXPORT void JNICALL Java_MyNative_printString(JNIEnv* env, jobject obj, jstring str) {
    const char* nativeString = env->GetStringUTFChars(str, 0);
    PrintString(nativeString);
    env->ReleaseStringUTFChars(str, nativeString);
}

JNIEXPORT jstring JNICALL Java_MyNative_getChineseString(JNIEnv* env, jobject obj) {
    const char* chineseString = GetChineseString();
    jstring result = env->NewStringUTF(chineseString);
    FreeString(chineseString);
    return result;
}



JNIEXPORT jobject JNICALL Java_MyNative_addStructs(JNIEnv* env, jobject obj, jobject structA, jobject structB) {
    jclass structClass = env->GetObjectClass(structA);
    jfieldID fidX = env->GetFieldID(structClass, "x", "I");
    jfieldID fidY = env->GetFieldID(structClass, "y", "I");

    int xA = env->GetIntField(structA, fidX);
    int yA = env->GetIntField(structA, fidY);
    int xB = env->GetIntField(structB, fidX);
    int yB = env->GetIntField(structB, fidY);

    MyStruct a = { xA, yA };
    MyStruct b = { xB, yB };
    MyStruct result = AddStructs(a, b);

    jobject newStruct = env->AllocObject(structClass);
    env->SetIntField(newStruct, fidX, result.x);
    env->SetIntField(newStruct, fidY, result.y);

    return newStruct;
}

// 创建 MyClass 对象
JNIEXPORT jlong JNICALL Java_MyNative_createMyClass(JNIEnv* env, jclass cls, jint value) {
    jlong ret = reinterpret_cast<jlong>(new MyClass(value));
    std::cout << "Java_MyNative_createMyClass" << ":" << ret << std::endl;
    return ret;
}

// 销毁 MyClass 对象
JNIEXPORT void JNICALL Java_MyNative_destroyMyClass(JNIEnv* env, jclass cls, jlong objPtr) {
    std::cout << "Java_MyNative_destroyMyClass: " << ":" << objPtr << std::endl;
    MyClass* obj = reinterpret_cast<MyClass*>(objPtr);
    std::cout << "Destroying MyClass with value: " << obj->GetValue() << std::endl;
    delete obj;
}

// 获取 MyClass 的值
JNIEXPORT jint JNICALL Java_MyNative_getMyClassValue(JNIEnv* env, jclass cls, jlong objPtr) {
    MyClass* obj = reinterpret_cast<MyClass*>(objPtr);
    return obj->GetValue();
}

2.3 MyNative.java

public class MyNative {

    // 加载 C++ 编译的 DLL
    static {
        System.loadLibrary("Dll1"); // 这个地方不需要写.dll
    }

    // 声明本地方法
    public static native int addNumbers(int a, int b);

    public static native double addDoubles(double a, double b);

    public static native void addDoublesByRef(double[] a, double[] b, double[] result);

    public static native char getCharValue(char c);

    public static native void printString(String str);

    public static native String getChineseString();

    public static native void freeString(String str);

    public static native MyStruct addStructs(MyStruct a, MyStruct b);

    public static native long createMyClass(long number);

    public static native void destroyMyClass(long handle);

    public static native int getMyClassValue(long handle);

    // 定义结构体
    public static class MyStruct {
        public int x;
        public int y;
    }

    // 定义类
    public static class MyClass {
        private long handle;

        public MyClass(int number) {
            this.handle = createMyClass(number);;
        }

        public long getValue() {
            return getMyClassValue(handle);
        }

        public void dispose() {
            destroyMyClass(this.handle);
        }
    }

    public static void main(String[] args) {

        // 测试 AddNumbers
        int sum = addNumbers(5, 3);
        System.out.println("Result of adding numbers: " + sum);

        // 测试 AddDoubles
        double doubleSum = addDoubles(5.5, 3.3);
        System.out.println("Result of adding doubles: " + doubleSum);

        // 测试 AddDoublesByRef
        double a = 5.5;
        double b = 3.3;
        double[] aArray = { a };
        double[] bArray = { b };
        double[] resultArray = new double[1];
        addDoublesByRef(aArray, bArray, resultArray);
        System.out.println("Result of adding doubles by ref: " + resultArray[0]);

        // 测试 GetCharValue
        char charResult = getCharValue('A');
        System.out.println("Result of GetCharValue: " + charResult);

        // 测试 PrintString
        printString("Hello from C++");

        // 测试 GetChineseString
        String chineseString = getChineseString();
        System.out.println("Chinese string from C++: " + chineseString);

       
        // 测试 AddStructs
        MyStruct structA = new MyStruct();
        structA.x = 1;
        structA.y = 2;
        MyStruct structB = new MyStruct();
        structB.x = 3;
        structB.y = 4;
        MyStruct structResult = addStructs(structA, structB);
        System.out.println("Result of adding structs: (" + structResult.x + ", " + structResult.y + ")");

        


        MyClass myClass = new MyClass(999);
        long number = myClass.getValue();
        System.out.println("Value from MyClass: " + number);
        myClass.dispose();
    }
}
  • 编译运行
javac -encoding UTF-8 .\MyNative.java
java MyNative
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

满天飞飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值