一个本地方法可以从另一个本地方法调用吗?
Can one native method be called from another native method?
我在 Java 中有一个 class,其中包含某些本机方法声明。它在 finalize 方法中包含对 detroy() 的调用,该方法现已弃用。作为最终确定的替代方法,我使用 try-with-resources 实现了 AutoCloseable。但是问题是,必须在我的 JSQ class 中覆盖的 AutoCloseable 提供的 close() 方法与我的代码中已经定义的现有本机 close 方法冲突。如果我能找到一个可以调用 destroy 的备用位置,那应该足以作为解决方案。因此,我试图从本机 close() 调用 destroy(),这将是使用 shdl 的最后一点。这可能/允许/推荐吗?我没有删除或更改本机 close() 的选项,这就是为什么我试图从本机关闭调用销毁。
JSQL.java
class JSQ implements AutoCloseable{
protected long shdl;
protected JSQ() { log("JSQ constructor"); }
protected JSQ(String stmt, boolean isd)
throws DhSQLException
{
// calls a set of native methods
set_shdl();
setstmt(stmt, shdl);
setd(isd, shdl);
prep(shdl);
}
// to be removed
public void finalize()
{
destroy(shdl);
}
// alternative to finalize
@Override
public void close()
{
destroy();
}
protected void open()
{
parOpen (shdl);
}
private native void set_shdl() throws DhSQLException;
private native void setstmt(String s, long shdl) throws DhSQLException;
private native void setd(boolean b, long shdl);
private native void prep(long shdl) throws DhSQLException;
private native void destroy(long shdl);
protected native void parOpen(long shdl);
// following method is called from sub-classes of JSQ
// super.close(shdl);
protected native void close(long shdl);
protected void execute() throws DhSQLException
{
parExec(shdl);
}
protected native void parExec(long shdl);
}
JSQ.cxx
#define SQ ((sq_stsm_t *)(shdl))
JNIEXPORT void JNICALL Java_com_project_package_JSQ_set_shdl
(JNIEnv *env, jobject obj_This)
{
jclass cls;
jmethodID mid;
cls = (env)->GetObjectClass (obj_This);
mid = (env)->GetMethodID (hThis,"set_JSQ_shdl","(J)V");
status_t status;
// memory allocation
sq_stsm_t * S = new sq_stsm_t(status);
if(status)
{
if (S) { delete S; }
return;
}
// I understand that we're attempting to call a Java method from a native method.
// But which method is it calling?
// Also, are we converting S from sq_stms_t type to jlong?
(env)->CallVoidMethod (obj_This,mid,(jlong) S);
return;
}
JNIEXPORT void JNICALL Java_com_project_package_JSQ_setstmt
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
status_t status;
// cstmt is obtained using jstmt
status = SQ->SetStmt(cstmt);
return;
}
JNIEXPORT void JNICALL Java_com_project_package_JSQ_destroy
(JNIEnv *, jobject, jlong shdl)
{
delete SQ;
}
JNIEXPORT void JNICALL Java_com_project_package_JSQ_close
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
status_t status;
status = SQ->CloseSQ();
// Java_com_project_package_JSQ_destroy(shdl); ?
//destroy(shdl); ?
return;
}
Java_com_project_package_JSQ_destroy(shdl); ?
摧毁(shdl); ?
或任何其他可以用于删除 finalize() 并找到合适的销毁位置的替代方法?
从一个本机方法调用另一个本机方法实际上是允许的。至少,我这样做时没有收到任何错误或警告。但是调用必须包含任何本机方法所期望的完整函数名称 - 即 Java_com_project_package_JSQ_destroy
并且参数应包括:
- JNI 环境
- jobject 对象
- 方法需要的参数。在这种情况下,shdl
因此调用必须是这样的:
Java_com_project_package_JSQ_destroy(env, <jobject_object_name>, shdl);
应该调用销毁方法。但是,它并没有真正遵守 Java 本机接口所服务的目的,本机接口是一个用于允许 Java 代码调用以其他语言编写的本机应用程序和库并被其调用的层(这里,C++)。
这样的链接是合法的。在您的特定用例中,它应该很简单。
但总的来说,有一些问题是不容忽视的:
被调用的方法需要正确的 JNI env 指针。因此,如果您从不同的线程调用它,则您有责任将它附加到 JVM。您不能跨线程传递 JNIEnv *
。
被调用的方法期望 JVM 在它 returns 之后立即释放所有本地引用。幸运的是,调用者可以在链接调用之前使用 PushLocalFrame()
(并且不要忘记 return 上的 PopLocalFrame()
。
被调用的方法期望没有待处理的 JNI 异常。调用者应该通过调用 ExceptionCheck()
或 ExceptionOccurred()
来检查它,如果它必须继续调用其他方法,也使用 ExceptionClear()
。调用者在被调用者 returns.
之后检查异常是明智的
我在 Java 中有一个 class,其中包含某些本机方法声明。它在 finalize 方法中包含对 detroy() 的调用,该方法现已弃用。作为最终确定的替代方法,我使用 try-with-resources 实现了 AutoCloseable。但是问题是,必须在我的 JSQ class 中覆盖的 AutoCloseable 提供的 close() 方法与我的代码中已经定义的现有本机 close 方法冲突。如果我能找到一个可以调用 destroy 的备用位置,那应该足以作为解决方案。因此,我试图从本机 close() 调用 destroy(),这将是使用 shdl 的最后一点。这可能/允许/推荐吗?我没有删除或更改本机 close() 的选项,这就是为什么我试图从本机关闭调用销毁。
JSQL.java
class JSQ implements AutoCloseable{
protected long shdl;
protected JSQ() { log("JSQ constructor"); }
protected JSQ(String stmt, boolean isd)
throws DhSQLException
{
// calls a set of native methods
set_shdl();
setstmt(stmt, shdl);
setd(isd, shdl);
prep(shdl);
}
// to be removed
public void finalize()
{
destroy(shdl);
}
// alternative to finalize
@Override
public void close()
{
destroy();
}
protected void open()
{
parOpen (shdl);
}
private native void set_shdl() throws DhSQLException;
private native void setstmt(String s, long shdl) throws DhSQLException;
private native void setd(boolean b, long shdl);
private native void prep(long shdl) throws DhSQLException;
private native void destroy(long shdl);
protected native void parOpen(long shdl);
// following method is called from sub-classes of JSQ
// super.close(shdl);
protected native void close(long shdl);
protected void execute() throws DhSQLException
{
parExec(shdl);
}
protected native void parExec(long shdl);
}
JSQ.cxx
#define SQ ((sq_stsm_t *)(shdl))
JNIEXPORT void JNICALL Java_com_project_package_JSQ_set_shdl
(JNIEnv *env, jobject obj_This)
{
jclass cls;
jmethodID mid;
cls = (env)->GetObjectClass (obj_This);
mid = (env)->GetMethodID (hThis,"set_JSQ_shdl","(J)V");
status_t status;
// memory allocation
sq_stsm_t * S = new sq_stsm_t(status);
if(status)
{
if (S) { delete S; }
return;
}
// I understand that we're attempting to call a Java method from a native method.
// But which method is it calling?
// Also, are we converting S from sq_stms_t type to jlong?
(env)->CallVoidMethod (obj_This,mid,(jlong) S);
return;
}
JNIEXPORT void JNICALL Java_com_project_package_JSQ_setstmt
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
status_t status;
// cstmt is obtained using jstmt
status = SQ->SetStmt(cstmt);
return;
}
JNIEXPORT void JNICALL Java_com_project_package_JSQ_destroy
(JNIEnv *, jobject, jlong shdl)
{
delete SQ;
}
JNIEXPORT void JNICALL Java_com_project_package_JSQ_close
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
status_t status;
status = SQ->CloseSQ();
// Java_com_project_package_JSQ_destroy(shdl); ?
//destroy(shdl); ?
return;
}
Java_com_project_package_JSQ_destroy(shdl); ?
摧毁(shdl); ?
或任何其他可以用于删除 finalize() 并找到合适的销毁位置的替代方法?
从一个本机方法调用另一个本机方法实际上是允许的。至少,我这样做时没有收到任何错误或警告。但是调用必须包含任何本机方法所期望的完整函数名称 - 即 Java_com_project_package_JSQ_destroy
并且参数应包括:
- JNI 环境
- jobject 对象
- 方法需要的参数。在这种情况下,shdl
因此调用必须是这样的:
Java_com_project_package_JSQ_destroy(env, <jobject_object_name>, shdl);
应该调用销毁方法。但是,它并没有真正遵守 Java 本机接口所服务的目的,本机接口是一个用于允许 Java 代码调用以其他语言编写的本机应用程序和库并被其调用的层(这里,C++)。
这样的链接是合法的。在您的特定用例中,它应该很简单。
但总的来说,有一些问题是不容忽视的:
被调用的方法需要正确的 JNI env 指针。因此,如果您从不同的线程调用它,则您有责任将它附加到 JVM。您不能跨线程传递
JNIEnv *
。被调用的方法期望 JVM 在它 returns 之后立即释放所有本地引用。幸运的是,调用者可以在链接调用之前使用
PushLocalFrame()
(并且不要忘记 return 上的PopLocalFrame()
。被调用的方法期望没有待处理的 JNI 异常。调用者应该通过调用
ExceptionCheck()
或ExceptionOccurred()
来检查它,如果它必须继续调用其他方法,也使用ExceptionClear()
。调用者在被调用者 returns. 之后检查异常是明智的