You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过JNI连接C++与Kotlin/Java类及双向对象传递可行性问询

Connecting C++ Classes to Kotlin/Java via JNI & Bidirectional Object Passing

Great questions—JNI absolutely lets you bridge C++ and Kotlin/Java classes, and bidirectional object passing is totally feasible. Let’s break this down step by step with concrete examples matching your class structure.


1. Linking C++ Classes with Kotlin/Java Using JNI

The core idea is to create a "bridge" layer where JNI translates between C++ objects and their Kotlin/Java counterparts. Here’s the workflow:

Step 1: Define Your Kotlin Classes

First, outline the Kotlin classes you want to map to C++:

// Kotlin: com/your/package/A.kt
class A {
    var someField: Int = 0
    // Add other fields/methods as needed
}

// Kotlin: com/your/package/B.kt
class B {
    var a: A = A()
    var anotherField: String = ""
}

Step 2: Generate JNI Header File

Use kotlinc (or javac for Java) to generate the JNI header that defines the bridge functions. For Kotlin:

kotlinc B.kt A.kt -h .

This creates a header file (e.g., com_your_package_B.h) with function signatures your C++ code will implement.

Step 3: Implement JNI Bridge in C++

Write C++ code that uses JNI methods to instantiate Kotlin objects and populate their fields from C++ objects. We’ll cover this in detail in the next section for bidirectional passing.


2. Bidirectional Object Passing

Yes, you can convert objects between C++ and Kotlin in both directions. Let’s use your A and B classes to demonstrate.

Example 1: C++ Object → Kotlin Object

Here’s how to take a C++ B instance and convert it to a Kotlin B object:

First, your C++ classes:

// C++ classes
#include <string>

class A {
public:
    int someField;
    A() : someField(42) {} // Default value for demo
};

class B {
public:
    A a;
    std::string anotherField;
    B() : anotherField("Hello from C++") {}
};

Then the JNI implementation to convert C++ B to Kotlin B:

#include <jni.h>
#include "com_your_package_B.h" // Generated header

JNIEXPORT jobject JNICALL Java_com_your_package_B_fromCpp(JNIEnv* env, jclass clazz) {
    // Create a C++ B object
    B cppB;

    // 1. Instantiate Kotlin B object
    jclass kotlinBClass = env->FindClass("com/your/package/B");
    jmethodID kotlinBConstructor = env->GetMethodID(kotlinBClass, "<init>", "()V");
    jobject kotlinB = env->NewObject(kotlinBClass, kotlinBConstructor);

    // 2. Instantiate and populate Kotlin A object from C++ A
    jclass kotlinAClass = env->FindClass("com/your/package/A");
    jmethodID kotlinAConstructor = env->GetMethodID(kotlinAClass, "<init>", "()V");
    jobject kotlinA = env->NewObject(kotlinAClass, kotlinAConstructor);

    jfieldID aSomeFieldID = env->GetFieldID(kotlinAClass, "someField", "I");
    env->SetIntField(kotlinA, aSomeFieldID, cppB.a.someField);

    // 3. Attach Kotlin A to Kotlin B
    jfieldID bAFieldID = env->GetFieldID(kotlinBClass, "a", "Lcom/your/package/A;");
    env->SetObjectField(kotlinB, bAFieldID, kotlinA);

    // 4. Populate other fields in Kotlin B
    jfieldID bAnotherFieldID = env->GetFieldID(kotlinBClass, "anotherField", "Ljava/lang/String;");
    jstring jStr = env->NewStringUTF(cppB.anotherField.c_str());
    env->SetObjectField(kotlinB, bAnotherFieldID, jStr);

    // Clean up local references (good practice to avoid leaks)
    env->DeleteLocalRef(kotlinAClass);
    env->DeleteLocalRef(jStr);

    return kotlinB;
}

Example 2: Kotlin Object → C++ Object

Now let’s convert a Kotlin B object back to a C++ B instance:

JNIEXPORT void JNICALL Java_com_your_package_B_toCpp(JNIEnv* env, jclass clazz, jobject kotlinB) {
    // 1. Extract fields from Kotlin B
    jclass kotlinBClass = env->GetObjectClass(kotlinB);
    jfieldID bAFieldID = env->GetFieldID(kotlinBClass, "a", "Lcom/your/package/A;");
    jfieldID bAnotherFieldID = env->GetFieldID(kotlinBClass, "anotherField", "Ljava/lang/String;");

    // 2. Extract Kotlin A and its fields
    jobject kotlinA = env->GetObjectField(kotlinB, bAFieldID);
    jclass kotlinAClass = env->GetObjectClass(kotlinA);
    jfieldID aSomeFieldID = env->GetFieldID(kotlinAClass, "someField", "I");
    jint someFieldValue = env->GetIntField(kotlinA, aSomeFieldID);

    // 3. Extract string field
    jstring jAnotherField = (jstring)env->GetObjectField(kotlinB, bAnotherFieldID);
    const char* anotherFieldCStr = env->GetStringUTFChars(jAnotherField, nullptr);

    // 4. Create and populate C++ B object
    B cppB;
    cppB.a.someField = someFieldValue;
    cppB.anotherField = std::string(anotherFieldCStr);

    // Use the C++ object as needed (e.g., log values)
    printf("C++ B: someField=%d, anotherField=%s\n", cppB.a.someField, cppB.anotherField.c_str());

    // Clean up resources
    env->ReleaseStringUTFChars(jAnotherField, anotherFieldCStr);
    env->DeleteLocalRef(kotlinAClass);
    env->DeleteLocalRef(kotlinA);
    env->DeleteLocalRef(kotlinBClass);
}

Key Notes for JNI Object Handling

  • Type Signatures: Always use correct JNI type signatures (e.g., I for int, Ljava/lang/String; for String, Lcom/your/package/A; for class A). Generate them with javap -s com.your.package.B.
  • Memory Management: Local references (like jobject instances) are automatically released when the JNI call ends, but explicitly calling DeleteLocalRef helps avoid memory leaks in long-running calls. Use NewGlobalRef if you need to retain objects beyond the current call.
  • Error Handling: Add checks for null values (e.g., if FindClass returns nullptr) to avoid crashes.

内容的提问来源于stack exchange,提问作者Flamur Berisha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:45:32