Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/382.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 可以从另一个本机方法调用一个本机方法吗?_Java_Java Native Interface_Deprecated_Function Call_Finalize - Fatal编程技术网

Java 可以从另一个本机方法调用一个本机方法吗?

Java 可以从另一个本机方法调用一个本机方法吗?,java,java-native-interface,deprecated,function-call,finalize,Java,Java Native Interface,Deprecated,Function Call,Finalize,我有一个Java类,它包含某些本机方法声明。它在finalize方法中包含对detroy()的调用,该方法现在已被弃用。作为最终确定的替代方案,我使用try with resources实现了AutoCloseable。但是问题是,AutoCloseable提供的close()方法必须在我的JSQ类中重写,它与我的代码中已经定义的现有本机close方法冲突。如果我能找到另一个可以调用destroy的地方,那就足够了。因此,我试图从本机close()调用destroy(),这是最后一个使用shdl

我有一个Java类,它包含某些本机方法声明。它在finalize方法中包含对detroy()的调用,该方法现在已被弃用。作为最终确定的替代方案,我使用try with resources实现了AutoCloseable。但是问题是,AutoCloseable提供的close()方法必须在我的JSQ类中重写,它与我的代码中已经定义的现有本机close方法冲突。如果我能找到另一个可以调用destroy的地方,那就足够了。因此,我试图从本机close()调用destroy(),这是最后一个使用shdl的点。这是否可能/允许/建议?我没有删除或更改native close()的选项,这就是我试图从native close调用destroy的原因

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\u com\u project\u package\u JSQ\u destroy
,参数应包括:

  • JNI环境
  • 作业对象
  • 方法所需的参数。在本例中,shdl
  • 因此,呼叫必须如下所示:

    Java_com_project_package_JSQ_destroy(env, <jobject_object_name>, shdl);
    
    Java\u com\u项目\u包\u JSQ\u销毁(env,shdl);
    

    它应该调用destroy方法。但是,它并不真正符合Java本机接口的目的,Java本机接口是一个允许Java代码调用并被其他语言编写的本机应用程序和库调用的层(这里是C++)。

    这种链接是合法的。在您的特定用例中,它应该是直接的

    但总的来说,有一些问题不容忽视:

  • 被调用的方法需要正确的JNI env指针。所以,如果您从另一个线程调用它,那么您有责任将它附加到JVM。不能跨线程传递
    JNIEnv*

  • 被调用的方法期望JVM在返回后立即释放所有本地引用。幸运的是,调用方可以在链接调用之前使用
    PushLocalFrame()
    (并且在返回时不要忘记
    PopLocalFrame()

  • 被调用的方法要求没有挂起的JNI异常。调用方应该通过调用
    ExceptionCheck()
    ExceptionOccurred()
    来检查它,如果它必须继续调用另一个方法,也可以使用
    ExceptionClear()
    。在被调用方返回后,调用方应谨慎地检查异常


  • 你为什么要使用本机代码?这是遗留代码,我对此无能为力。你是指这种方法吗?显然,不是。正如我所提到的,它是一种本机方法。方法定义在JSQ.cxx下提供。它只是在SQ上执行删除。这很好。请注意,
    destroy
    不会出现在Java堆栈跟踪应该生成一个Java异常。如果您也需要,那么您必须通过JNI调用该方法。