java - 使用 native API : JVM_LoadClass0, JVM_AllocateNewArray 和 JVM_AllocateNewObject 的替代解决方案

标签 java c++ c jvm java-9

与在 Java 9 中一样,一些原生 API 因已弃用而被删除,我没有设法找到替代解决方案来替换它们。我是一名 C++ 开发人员,几乎没有 java 经验。我使用的原生 API 是:JVM_LoadClass0JVM_AllocateNewObjectJVM_AllocateNewArray

我的Java源代码是:

protected Class resolveClass(MercObjectStreamClass v) throws IOException, ClassNotFoundException
{
    /* Resolve by looking up the stack for a non-zero class
     * loader. If not found use the system loader.
     */
    String name = v.getName();
    try
    {
        //we are using the loadClass0 method which calls the native JVM_LoadClass0
        //JVM_LoadClass0 is deprecated and we need to replace the call
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
      if(loader == null) {
          return loadClass0(null,name);
        }

      Class scriptCls =  loader.loadClass(scriptClassname);
        return loadClass0(scriptCls,name);
    }
    catch (ClassNotFoundException ex)
    {
        Class cl = (Class)primClasses.get(name);
        if (cl != null)
            return cl;
        else
            throw ex;
    }
}
private native Class loadClass0(Class cl, String classname) throws ClassNotFoundException;

然后 native 代码只是对 JVM_LoadClass0 的简单调用:

JNIEXPORT jclass JNICALL
Java_mercio_MercObjectInputStream_loadClass0(JNIEnv * env,
    jobject this,
    jclass curClass,
    jstring currClassName)
{
    return JVM_LoadClass0(env, this, curClass, currClassName);
}

native 部分与其他 API 类似。

有人可以建议这种方法的替代方法吗?

最佳答案

我查阅了JVM_LoadClass0的源码,发现如下注释

// Load a class relative to the most recent class on the stack  with a non-null
// classloader.
// This function has been deprecated and should not be considered part of the
// specified JVM interface.

附加 currClass 参数的用途只能从实际代码中猜测,但显然只有在 currClass 不是的情况下才使用“堆栈上最近的类” null,否则使用currClass的加载器。

这引发了一些关于 resolveClass 方法意图的问题。

  • 在正常环境中,像您的 MercObjectInputStream 这样的自定义类不应由引导加载程序加载,因此,堆栈中具有非空类加载器的最新类应该是你自己的 MercObjectInputStream 类。使用您自己的类加载器来解析一个类非常简单,您只需调用 Class.forName(name)

  • 你正在探测 Thread.currentThread().getContextClassLoader() 默认为 ClassLoader.getSystemClassLoader() 并且很少设置为 null。因此,在堆栈上探测类的行为似乎是一种罕见的极端情况。

  • 当上下文加载器不是null时,你不是用它来加载类,而是做loader.loadClass(scriptClassname); return loadClass0(scriptCls,name);,首先加载一个scriptClassname,然后使用结果的加载器来解析name。如果这是故意的,您可以使用 Class scriptCls = loader.loadClass(scriptClassname); return Class.forName(name, true, scriptCls.getClassLoader()); 无需原生方法即可实现。

您可以在不使用 native 代码的情况下使用与 Java 9 中的原始代码完全相同的操作

protected Class resolveClass(MercObjectStreamClass v)
                                       throws IOException, ClassNotFoundException
{
    String name = v.getName();
    try
    {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if(loader != null)
            loader = loader.loadClass(scriptClassname).getClassLoader();
        else
            loader = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                        .walk(s -> s.map(sf -> sf.getDeclaringClass().getClassLoader())
                                    .filter(Objects::nonNull)
                                    .findFirst().orElse(null));

        return Class.forName(name, true, loader);
    }
    catch (ClassNotFoundException ex)
    {
        Class cl = (Class)primClasses.get(name);
        if (cl != null)
            return cl;
        else
            throw ex;
    }
}

但是,如前所述,您应该首先重新考虑该方法实际上应该做什么。

关于java - 使用 native API : JVM_LoadClass0, JVM_AllocateNewArray 和 JVM_AllocateNewObject 的替代解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48642552/

相关文章:

c - 树莓派 spidev.h SPI 通信

java - 打开图像文件-BLACKBERRY/J2ME

java - 单击按钮后,应用程序立即停止工作

c - 错误当我使用 fopen 从文件中读取时,不存在此类文件或目录

c++ - 在C++中选择错误的文件时,防止boost xml分析器崩溃

c++ - 我可以有一个带有可变对象的模板吗?

c - 如何返回char数组?

java - hibernate :不能级联删除 child 的单向 parent

java - 有没有办法序列化和反序列化 Java 中的 Singleton 类保持其单例性质?

c++ - 构建独立的Libtiff(Linux)