在 Java 9 中,一些原生 API 因弃用而被删除,我没能找到替代解决方案来替代它们。我是一名 C++ 开发人员,在 Java 方面经验很少。我使用的 native API 是:JVM_LoadClass0
、JVM_AllocateNewObject
和 JVM_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/