2023-01-20 313
我正在使用C ++在JNI工作,并且创建了一种方法,其中一系列参数被传递给我的本机方法作为jobightaray.我想使用这些参数在JNI中调用构造函数.但是,NewObject方法不使用省略号而不是接受求解阵列.我将如何完成这项任务?我不知道在调用该方法之前将采用多少个构造函数,并且签名字符串也从Java传递.我正在调用的构造函数不会将数组作为参数,而是将同一类的不同版本传递给C ++函数,每个函数都包含不同的方法签名.我需要我的C ++方法,以便能够使用其传递的参数创建任何对象.我正在使用Visual Studio作为我的IDE.我了解我可能需要一系列的JVALUE,但我不明白如何从Jobightaray获得它.
编辑:
对不起,我误解了您的问题.您可以使用JNI API提供的其他两种方法来创建对象( docs ):
jobject NewObjectA(JNIEnv *env, jclass clazz,
jmethodID methodID, const jvalue *args);
jobject NewObjectV(JNIEnv *env, jclass clazz,
jmethodID methodID, va_list args);
newObjecta
程序员将所有要传递给构造函数的参数放在立即遵循MethodID参数的JValues中. NewObjecta()接受此数组中的参数,然后将它们传递给程序员希望调用的Java方法.
newObjectV
程序员将所有要传递给构造函数的参数都在va_list类型的args参数中,该参数立即遵循methotiD参数. newObjectV()接受这些参数,然后将它们传递给程序员希望调用的Java方法.
所以,我制作了一个示例程序,显示了如何使用它.
foo.java
public class Foo {
private int bar;
private String baaz;
public Foo(int bar) {
this(bar, "");
}
public Foo(int bar, String baaz) {
this.bar = bar;
this.baaz = baaz;
}
public void method1() {
this.bar++;
System.out.println(bar);
System.out.println(baaz);
}
}
bar.java
public class Bar {
public Bar() {
}
public static native Foo createFoo(String signature, Object ... params);
}
bar.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Bar */
#ifndef _Included_Bar
#define _Included_Bar
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Bar
* Method: createFoo
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)LFoo;
*/
JNIEXPORT jobject JNICALL Java_Bar_createFoo
(JNIEnv *, jclass, jstring, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
bar.c
#include "Bar.h"
#include <stdlib.h>
jobject JNICALL Java_Bar_createFoo
(JNIEnv * env, jclass class, jstring signature, jobjectArray params) {
// method signature in char *
const char * signatureChar = (*env)->GetStringUTFChars(env, signature, 0);
jvalue * args;
int i, size;
// retrieve foo class
jclass fooClass = (*env)->FindClass(env, "LFoo;");
// retrieve foo construtor
jmethodID fooConstructor = (*env)->GetMethodID(env, fooClass, "<init>", signatureChar);
// operate over params
// ...
// TODO: find out a way to retrieve size from constructor
size = 2;
args = malloc(size * sizeof(jvalue));
for (i = 0; i < size; i++) {
args[i].l = (*env)->GetObjectArrayElement(env, params, i);
}
return (*env)->NewObjectA(env, fooClass, fooConstructor, args);
}
main.java
public class Main {
static {
System.loadLibrary("YOUR_LIBRARY_NAME_HERE");
}
public static void main(String[] args) {
Foo foo = Bar.createFoo("(ILjava/lang/String;)V", -12312141, "foo");
System.out.println(foo);
foo.method1();
foo = Bar.createFoo("(I)V", -12312141, "foo");
System.out.println(foo);
foo.method1();
foo = Bar.createFoo("(I)V", -12312141);
System.out.println(foo);
foo.method1();
}
}
警告:它仍然不是100%funciontal
这有点棘手,因为您已经传递了jobjectArray.这意味着原始类型已经被装箱(例如int是java.lang.Integer在您的数组中的实例),并且在将它们传递到构造函数上之前,您必须将它们拆开.
您将要做的是解析方法签名字符串(它不如您想象的那么糟)如有必要,).
可悲的是,JNI没有内置的方式可以执行拆箱,因此您必须通过调用盒装值的适当方法来手动执行此操作(例如Integer.intValue获得int) .
基本思想:
jobject createObject(JNIEnv *env, jclass clazz, jmethodID constructor, const char *argstr, jobjectArray *args) {
int n = env->GetArrayLength(args);
jvalue *values = new jvalue[n];
const char *argptr = argstr;
for(int i=0; i<n; i++) {
jobject arg = env->GetObjectArrayElement(args, i);
if(*argptr == 'B') { /* byte */
values[i].b = object_to_byte(arg);
}
/* cases for all of the other primitive types...*/
else if(*argptr == '[') { /* array */
while(*argptr == '[') argptr++;
if(*argptr == 'L')
while(*argptr != ';') argptr++;
values[i].l = arg;
} else if(*argptr == 'L') { /* object */
while(*argptr != ';') argptr++;
values[i].l = arg;
}
argptr++;
env->DeleteLocalRef(arg);
}
return env->NewObjectA(clazz, methodID, values);
}
object_to_byte和其他转换函数将定义为取消相关类型的函数(例如,object_to_byte将使用JNI在给定对象上调用java.lang.Byte.byteValue).
感谢 @lukehutchinson的提示,我继续寻找更好的解决方案,并很高兴地报告说,实际上使用Reflection API有一种更简单的方法.您可以使用jni函数ToReflectedMethod将methodID转换为java.lang.reflect.Method或java.lang.reflect.Constructor,然后您可以分别调用invoke或newInstance,它将处理所有必要的拆箱转换.
这是一个概念证明,省略了错误检查以确保清晰度.
test.java:
public class test {
static {
System.loadLibrary("native");
}
public static void main(String[] args) {
/* This is the constructor String(byte[], int, int).
This call will print out BCD - the result of creating
a string from bytes 1-3 of the array */
System.out.println(new test().makeObject("java/lang/String", "([BII)V", new byte[] { 0x41, 0x42, 0x43, 0x44, 0x45 }, 1, 3));
}
private native Object makeObject(String clazz, String signature, Object... args);
}
libnative.c:
#include <jni.h>
JNIEXPORT jobject JNICALL Java_test_makeObject(JNIEnv *env, jobject this, jstring clazzName, jstring signature, jobjectArray args) {
const char *clazzNameStr = (*env)->GetStringUTFChars(env, clazzName, NULL);
const char *signatureStr = (*env)->GetStringUTFChars(env, signature, NULL);
jclass clazz = (*env)->FindClass(env, clazzNameStr);
jmethodID methodID = (*env)->GetMethodID(env, clazz, "<init>", signatureStr);
jobject reflectedMethod = (*env)->ToReflectedMethod(env, clazz, methodID, JNI_FALSE);
jclass constructorClazz = (*env)->FindClass(env, "java/lang/reflect/Constructor");
jmethodID newInstanceMethod = (*env)->GetMethodID(env, constructorClazz, "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;");
jobject result = (*env)->CallObjectMethod(env, reflectedMethod, newInstanceMethod, args);
(*env)->ReleaseStringUTFChars(env, clazzName, clazzNameStr);
(*env)->ReleaseStringUTFChars(env, signature, signatureStr);
return result;
}
以上所述是小编给大家介绍的调用jni jni带有参数的jni,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!
原文链接:https://77isp.com/post/26168.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态