通过JNI创建java对象和访问java属性

server/2024/9/23 2:33:51/

一:通过jni创建Java对象

1.NewObject创建对象

在 Android NDK 中,使用 JNI(Java Native Interface)可以通过 NewObject 函数创建 Java 对象。NewObject 函数允许你在 C/C++ 代码中实例化 Java 类的对象。

1. 函数说明

  • NewObject: 创建一个新的 Java 对象。

2. 使用示例

以下是一个示例,演示如何在 C++ 中使用 NewObject 创建 Java 对象。

2.1 Java 类定义

首先,定义一个简单的 Java 类,例如 MyClass,它有一个构造函数和一个方法:

java">// MyClass.java
package com.example.yourapp;public class MyClass {private String message;public MyClass(String message) {this.message = message;}public void printMessage() {System.out.println(message);}
}

2.2 C++ 代码创建对象

在你的 C++ 代码中,使用 NewObject 创建 MyClass 的实例:

#include <jni.h>
#include <android/log.h>#define LOG_TAG "NativeExample"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C" JNIEXPORT void JNICALL
Java_com_example_yourapp_MainActivity_createMyClass(JNIEnv *env, jobject obj) {// 获取 MyClass 的类引用jclass myClass = env->FindClass("com/example/yourapp/MyClass");if (myClass == nullptr) {LOGI("Failed to find MyClass");return;}// 获取构造函数的 IDjmethodID constructor = env->GetMethodID(myClass, "<init>", "(Ljava/lang/String;)V");/**要查找的方法的名称。对于构造函数,名称是 "<init>"。对于对象类型,使用 L 开头,后跟类的完全限定名,然后以 ; 结束。例如,Ljava/lang/String; 表示 String 类型。
数组类型用 [ 前缀表示,例如,[I 表示 int 数组。*/if (constructor == nullptr) {LOGI("Failed to find MyClass constructor");return;}// 创建一个 Java 字符串对象jstring message = env->NewStringUTF("Hello from C++");// 创建 MyClass 的实例jobject myClassInstance = env->NewObject(myClass, constructor, message);if (myClassInstance == nullptr) {LOGI("Failed to create MyClass instance");return;}// 调用 printMessage 方法jmethodID printMethod = env->GetMethodID(myClass, "printMessage", "()V");if (printMethod == nullptr) {LOGI("Failed to find printMessage method");return;}env->CallVoidMethod(myClassInstance, printMethod);// 释放局部引用env->DeleteLocalRef(message);env->DeleteLocalRef(myClassInstance);env->DeleteLocalRef(myClass);
}

3. 在 Java 中调用

在你的 Java 代码中,声明本地方法并调用它:

java">public class MainActivity extends AppCompatActivity {static {System.loadLibrary("yourlib"); // 确保加载包含创建对象代码的库}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 调用创建对象的本地方法createMyClass();}public native void createMyClass();
}

4. 总结

通过使用 NewObject,你可以在 C++ 代码中创建 Java 对象并调用其方法。这在需要从本地代码与 Java 代码交互时非常有用。确保正确处理类和方法的查找,以及局部引用的管理,以避免内存泄漏。

2.allocobject创建对象

在 Android NDK 中,AllocObject 是 JNI 提供的一个函数,用于分配一个新的 Java 对象,但不调用其构造函数。这个函数通常用于创建对象的实例,之后可以通过其他 JNI 函数来初始化对象的字段或调用方法。

1. 函数说明

  • AllocObject: 分配一个新的 Java 对象,但不调用构造函数。

2. 使用示例

以下是一个示例,演示如何在 C++ 中使用 AllocObject 创建 Java 对象。

2.1 Java 类定义

首先,定义一个简单的 Java 类,例如 MyClass,它有一个字段和一个方法:

java">// MyClass.java
package com.example.yourapp;public class MyClass {public String message;public void printMessage() {System.out.println(message);}
}

2.2 C++ 代码使用 AllocObject

在你的 C++ 代码中,使用 AllocObject 创建 MyClass 的实例,并初始化其字段:

#include <jni.h>
#include <android/log.h>#define LOG_TAG "NativeExample"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C" JNIEXPORT void JNICALL
Java_com_example_yourapp_MainActivity_createMyClass(JNIEnv *env, jobject obj) {// 获取 MyClass 的类引用jclass myClass = env->FindClass("com/example/yourapp/MyClass");if (myClass == nullptr) {LOGI("Failed to find MyClass");return;}// 使用 AllocObject 分配 MyClass 的实例jobject myClassInstance = env->AllocObject(myClass);if (myClassInstance == nullptr) {LOGI("Failed to allocate MyClass instance");return;}// 获取 message 字段的 IDjfieldID messageField = env->GetFieldID(myClass, "message", "Ljava/lang/String;");if (messageField == nullptr) {LOGI("Failed to find message field");return;}// 创建一个 Java 字符串对象jstring message = env->NewStringUTF("Hello from C++");// 设置 message 字段的值env->SetObjectField(myClassInstance, messageField, message);// 调用 printMessage 方法jmethodID printMethod = env->GetMethodID(myClass, "printMessage", "()V");if (printMethod == nullptr) {LOGI("Failed to find printMessage method");return;}env->CallVoidMethod(myClassInstance, printMethod);// 释放局部引用env->DeleteLocalRef(message);env->DeleteLocalRef(myClassInstance);env->DeleteLocalRef(myClass);
}

3. 在 Java 中调用

在你的 Java 代码中,声明本地方法并调用它:

java">public class MainActivity extends AppCompatActivity {static {System.loadLibrary("yourlib"); // 确保加载包含创建对象代码的库}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 调用创建对象的本地方法createMyClass();}public native void createMyClass();
}

4. 总结

通过使用 AllocObject,你可以在 C++ 代码中分配 Java 对象的实例,而不调用构造函数。这在需要手动初始化对象的字段时非常有用。确保正确处理类和字段的查找,以及局部引用的管理,以避免内存泄漏。

javalangStringV_239">3.env->GetMethodID(myClass, “”, “(Ljava/lang/String;)V”);参数解释

在 JNI 中,GetMethodID 函数用于获取 Java 类中指定方法的 ID。这个函数的原型如下:

jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

参数解释

  1. JNIEnv *env:
    • JNI 环境指针,提供访问 JNI 函数的接口。每个线程都有自己的 JNIEnv 指针。
  2. jclass clazz:
    • 要查找方法的 Java 类的引用。通常通过 FindClass 函数获得。
  3. const char *name:
    • 要查找的方法的名称。对于构造函数,名称是 "<init>"
  4. const char *sig:
    • 方法的签名,描述方法的参数类型和返回类型。签名的格式如下:
      • 基本类型用单个字符表示,例如:
        • V 表示 void
        • Z 表示 boolean
        • B 表示 byte
        • C 表示 char
        • S 表示 short
        • I 表示 int
        • J 表示 long
        • F 表示 float
        • D 表示 double
      • 对于对象类型,使用 L 开头,后跟类的完全限定名,然后以 ; 结束。例如,Ljava/lang/String; 表示 String 类型。
      • 数组类型用 [ 前缀表示,例如,[I 表示 int 数组。

示例解析

对于以下代码:

jmethodID constructor = env->GetMethodID(myClass, "<init>", "(Ljava/lang/String;)V");
  • myClass: 这是通过 FindClass 获取的 MyClass 的类引用。
  • "<init>": 这是构造函数的名称。在 Java 中,构造函数的名称与类名相同,但在 JNI 中,构造函数使用 "<init>" 表示。
  • "(Ljava/lang/String;)V": 这是构造函数的签名。
    • L 表示一个对象类型。
    • java/lang/String; 表示 String 类。
    • ) 表示参数列表的结束。
    • V 表示返回类型为 void(构造函数没有返回值)。

总结

通过使用 GetMethodID,你可以获取 Java 类中指定方法的 ID,以便在 C++ 代码中调用该方法。确保提供正确的类引用、方法名称和方法签名,以避免查找失败或调用错误的方法。

java_292">二.通过jni访问java属性

通过 JNI 访问 Java 属性(字段)涉及到几个步骤,包括获取类的引用、获取字段的 ID、以及使用相应的 JNI 函数来读取或修改字段的值。以下是详细的步骤和示例代码。

1. 获取类的引用

首先,你需要获取要访问的 Java 类的引用。可以使用 FindClass 函数。

2. 获取字段的 ID

使用 GetFieldID 函数获取字段的 ID。你需要提供字段的名称和签名。

3. 访问字段

使用 Get<Type>FieldSet<Type>Field 函数来读取或修改字段的值。

示例

假设我们有一个 Java 类 MyClass,它有一个 String 类型的字段 message

1. Java 类定义

java">// MyClass.java
package com.example.yourapp;public class MyClass {public String message;public MyClass(String message) {this.message = message;}
}

2. C++ 代码访问字段

以下是 C++ 代码示例,演示如何通过 JNI 访问 MyClassmessage 字段。

#include <jni.h>
#include <android/log.h>#define LOG_TAG "NativeExample"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C" JNIEXPORT void JNICALL
Java_com_example_yourapp_MainActivity_accessField(JNIEnv *env, jobject obj) {// 获取 MyClass 的类引用jclass myClass = env->FindClass("com/example/yourapp/MyClass");if (myClass == nullptr) {LOGI("Failed to find MyClass");return;}// 获取构造函数的 IDjmethodID constructor = env->GetMethodID(myClass, "<init>", "(Ljava/lang/String;)V");if (constructor == nullptr) {LOGI("Failed to find MyClass constructor");return;}// 创建 MyClass 的实例jstring message = env->NewStringUTF("Hello from C++");jobject myClassInstance = env->NewObject(myClass, constructor, message);if (myClassInstance == nullptr) {LOGI("Failed to create MyClass instance");return;}// 获取 message 字段的 IDjfieldID messageField = env->GetFieldID(myClass, "message", "Ljava/lang/String;");if (messageField == nullptr) {LOGI("Failed to find message field");return;}// 读取 message 字段的值jstring messageValue = (jstring)env->GetObjectField(myClassInstance, messageField);const char *messageChars = env->GetStringUTFChars(messageValue, nullptr);LOGI("Message: %s", messageChars);// 释放字符串env->ReleaseStringUTFChars(messageValue, messageChars);// 修改 message 字段的值jstring newMessage = env->NewStringUTF("Updated message from C++");env->SetObjectField(myClassInstance, messageField, newMessage);// 读取更新后的 message 字段的值jstring updatedMessageValue = (jstring)env->GetObjectField(myClassInstance, messageField);const char *updatedMessageChars = env->GetStringUTFChars(updatedMessageValue, nullptr);LOGI("Updated Message: %s", updatedMessageChars);// 释放字符串env->ReleaseStringUTFChars(updatedMessageValue, updatedMessageChars);// 释放局部引用env->DeleteLocalRef(message);env->DeleteLocalRef(myClassInstance);env->DeleteLocalRef(myClass);env->DeleteLocalRef(newMessage);
}

3. 在 Java 中调用

在你的 Java 代码中,声明本地方法并调用它:

java">public class MainActivity extends AppCompatActivity {static {System.loadLibrary("yourlib"); // 确保加载包含访问字段代码的库}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 调用访问字段的本地方法accessField();}public native void accessField();
}

总结

通过 JNI,你可以方便地访问和修改 Java 对象的字段。确保正确处理类和字段的查找,以及局部引用的管理,以避免内存泄漏


http://www.ppmy.cn/server/118378.html

相关文章

Java | Leetcode Java题解之第409题最长回文串

题目&#xff1a; 题解&#xff1a; class Solution {public int longestPalindrome(String s) {int[] count new int[128];int length s.length();for (int i 0; i < length; i) {char c s.charAt(i);count[c];}int ans 0;for (int v: count) {ans v / 2 * 2;if (v …

初始爬虫7

针对数据提取的项目实战&#xff1a; 补充初始爬虫6的一个知识点&#xff1a; etree.tostring能够自动补全html缺失的标签&#xff0c;显示原始的HTML结构 # -*- coding: utf-8 -*- from lxml import etreetext <div> <ul> <li class"item-1">…

Prism库:详解其核心组件和使用方法

Prism库简介 Prism库是一个开源项目&#xff0c;由 Microsoft 社区开发和维护。它是一组用于创建 WPF、UWP 和 Xamarin 应用程序的工具和库&#xff0c;提供了一种基于模块化和依赖注入的架构模式&#xff0c;同时它提供了一系列的工具&#xff0c;帮助开发人员构建可扩展、可…

C# 手动写入日志,过大写入新文件

老项目没有用logf4j等日志框架&#xff0c;使用的是手动写入文件的方式存储日志。当日志过大会出现写入缓慢问题。下面采用IO异步写入以及文件过大分片等方式解决问题。 private static readonly object _lock new object(); private const long MaxFileSize 10 * 1024 * 10…

重生归来之挖掘stm32底层知识(1)——寄存器

概念理解 要使用stm32首先要知道什么是引脚和寄存器。 如下图所示&#xff0c;芯片通过这些金属丝与电路板连接&#xff0c;这些金属丝叫做引脚。一般做软件开发是不需要了解芯片是怎么焊的&#xff0c;只要会使用就行。我们平常通过编程来控制这些引脚的输入和输出&#xff0c…

ubuntu 22.04 ~24.04 如何修改登录背景

ubuntu 22.04 ~24.04 如何修改登录背景 背景&#xff1a;由于22.04 登录gdm的变更&#xff0c;之前的修改登录背景的方案已经无法使用。现在给大家分享新的使用方法&#xff1a; 1&#xff0c;下载如下路径的脚本&#xff1a; https://download.csdn.net/download/xdhyqd/89…

Android mmap分析

Android mmap分析 mmap基础概念 mmap是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff0c;进程就可以采用指针的方式读写操作…

[Redis] Redis中的set和zset类型

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…