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

标签 java c++ c jvm java-9

在 Java 9 中,一些原生 API 因弃用而被删除,我没能找到替代解决方案来替代它们。我是一名 C++ 开发人员,在 Java 方面经验很少。我使用的 native 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 这样的自定义类不应由 Bootstrap 加载器加载,因此,堆栈中具有非空类加载器的最新类应该是您自己的 MercObjectInputStream类(class)。使用你自己的类加载器来解析一个类非常简单,你可以简单地调用 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/

相关文章:

java - 从 ArrayList 中移除奇数元素

再次调用构造函数时修改对象的C++私有(private)成员

c - 每相差 7 的倍数加 1

java - 由于某种原因 getArrayList 被视为 int

JavaFX 回调 Lambda

java - 如何获取用户在listview上单击的项目的唯一id

c++ - 用空格分割字符串路径

c++ - 如何使用 AWS CPP SDK 检查 AWS S3 key 是否存在?

C 使用 fork() 共享内存

c - 如何检索所有 TCP UDP 打开端口?