gpt4 book ai didi

java - 加载具有父子关系的类时出现 LinkageError

转载 作者:行者123 更新时间:2023-11-30 06:15:49 25 4
gpt4 key购买 nike

我遵循了 http://www.jacoco.org/jacoco/trunk/doc/examples/java/CoreTutorial.java 上的 CoreTutorial 示例类(class)了解如何将 Jacoco 合并到项目中。

但是,我面临与使用的 MemoryClassLoader 类相关的 java.lang.LinkageError 问题。

/**
* A class loader that loads classes from in-memory data.
*/
public static class MemoryClassLoader extends ClassLoader {

private final Map<String, byte[]> definitions = new HashMap<String, byte[]>();

/**
* Add a in-memory representation of a class.
*
* @param name
* name of the class
* @param bytes
* class definition
*/
public void addDefinition(final String name, final byte[] bytes) {
definitions.put(name, bytes);
}

@Override
protected Class<?> loadClass(final String name, final boolean resolve)
throws ClassNotFoundException {
final byte[] bytes = definitions.get(name);
if (bytes != null) {
return defineClass(name, bytes, 0, bytes.length);
}
return super.loadClass(name, resolve);
}

}

具体来说,我有两个类,MyClass 和 MySubClass,其中 MySubClass 扩展了 MyClass。我对这两个类都进行了检测,以便获得与每个类相关的覆盖信息。我发现,如果我首先检测 MySubClass,MemoryClassLoader 将使用 MySubClass 的检测字节调用 DefineClass。然而,这样做时,父类 MyClass 也会被父类加载器加载。因此,当我下次检测并加载 MyClass 时,我收到 java.lang.LinkageError ,它声称已经存在已由 ClassLoader 加载的 MyClass 的定义。这里的问题是加载的 MyClass 的初始版本没有被检测。

如果我以相反的顺序加载类,则不会出现此问题。

我在这里尝试了一些不同的东西:https://github.com/huangwaylon/randoop/blob/bloodhound/src/main/java/randoop/main/MemoryClassLoader.java通过在递归调用 loadClass 时立即尝试检测父类。然而,由于我还没有弄清楚的原因,这并不完全有效。我观察到,如果我使用这种错误的方法,两个类的覆盖信息都不会改变。

我的总体问题是,如何检测和加载在父子关系中彼此相关的类,以便行为不受顺序影响?我可以替换类的定义吗?另一个问题似乎是 super.load ,它将是我无法控制的 MemoryClassLoader 的父 ClassLoader 。

最佳答案

首先,您应该覆盖 findClass而不是 loadClass。具有特定名称的类只能在加载器中定义一次的限制总是适用,并且您可能总是会遇到多次请求同一类的情况(在任何重要场景中)。 p>

ClassLoader 继承的 loadClass 实现已经处理了这个问题,并返回现有的定义(如果有)。由于它还首先查询父加载器,因此如果加载器应该定义其名称也被其他类加载器使用的类,那么您应该注意指定正确的父加载器。使用 loadClass 的默认实现,您的 findClass 方法可以保持简单:

public static class MemoryClassLoader extends ClassLoader {
private final Map<String, byte[]> definitions = new HashMap<>();

public void addDefinition(final String name, final byte[] bytes) {
definitions.put(name, bytes);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
final byte[] bytes = definitions.get(name);
if (bytes != null) {
return defineClass(name, bytes, 0, bytes.length);
}
return super.findClass(name);
}
}

确保所有想要的类都被检测,可以通过两种方式完成。

  1. 按需检测它们,即让 findClass 方法触发所请求类的检测。

  2. 在第一次调用 loadClass 之前,检测所有预期类的字节代码并将结果放入加载器中。

    final MemoryClassLoader memoryClassLoader = new MemoryClassLoader();
    memoryClassLoader.addDefinition("MyClass", instrumentedMyClass);
    memoryClassLoader.addDefinition("MySubClass", instrumentedMySubClass);
    final Class<?> myClass = memoryClassLoader.loadClass("MyClass");

    在这里,addDefinition 调用的顺序并不重要,也无论您调用 loadClass("MyClass") 还是 loadClass("MySubClass") 首先。这甚至适用于循环依赖。

关于java - 加载具有父子关系的类时出现 LinkageError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49227392/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com