当前位置: 首页 > 知识库问答 >
问题:

在java类装入器层次结构中,两个类装入器(假设都是URLClassLoader)如何装入一个类

公西星海
2023-03-14

最近我开始学习类加载器在Java中是如何工作的。以下是我注意到的三点:

点-1:每个类加载器都有一个父类加载器。当类加载器被要求加载类或资源时,它会在尝试加载项本身之前咨询其父类加载器。父级反过来咨询其父级,依此类推。因此,只有当所有祖先类加载器都找不到项时,当前类加载器才会参与其中。

Point-2:同一个类由两个加载器加载,被视为两个不同的类实体。我们甚至不能将一个类(加载器1)对象转换为另一个类(加载器2)。它会抛出ClassCastExcture。

第-3点:子类加载器可以检查父类加载器的缓存,但是父类看不到子类加载的类。

基于以上几点,我有两个问题:

情境:我在同一个应用程序中创建了一个URLClassloader对象url1和另一个URLClassloader对象url2。我们知道默认情况下,两个类加载器都将具有相同的父类加载器。

问题1:url1类加载器已从位置x/abc加载类a.class。罐子url2同样希望从相同的位置加载相同的类。url2是新加载的还是使用url1加载的同一个?我试图检查,只有一次静态块被执行,所以beleived类只被加载一次。根据我的理解,不满足第1点和第3点。

问题2:url2类加载器是否可以检查url1类加载器的缓存。与第3点有关。

共有1个答案

秦安宁
2023-03-14

类加载器是完全独立的,因此可以得到两个不同的类。

由于您没有发布MCVE(最小、完整和可验证的示例),这里是一个使用任意选择的. jar文件的示例。

public static void main(String[] args) throws Exception {
    String jarFile = "/path/to/commons-lang3-3.8.1.jar";

    URLClassLoader url1 = new URLClassLoader(new URL[] { new File(jarFile).toURI().toURL() });
    URLClassLoader url2 = new URLClassLoader(new URL[] { new File(jarFile).toURI().toURL() });

    Class<?> fractionClass1 = url1.loadClass("org.apache.commons.lang3.math.Fraction");
    Class<?> fractionClass2 = url2.loadClass("org.apache.commons.lang3.math.Fraction");

    Object oneHalf1 = fractionClass1.getField("ONE_HALF").get(null);
    Object oneHalf2 = fractionClass2.getField("ONE_HALF").get(null);

    System.out.println("url1 = " + url1);
    System.out.println("url2 = " + url2);
    System.out.println(" Same? " + (url1 == url2));
    System.out.println("fractionClass1 = " + fractionClass1);
    System.out.println("fractionClass2 = " + fractionClass2);
    System.out.println(" Same? " + (fractionClass1 == fractionClass2));
    System.out.println("oneHalf1 = " + oneHalf1);
    System.out.println("oneHalf2 = " + oneHalf2);
    System.out.println(" Same? " + (oneHalf1 == oneHalf2));
}

输出

url1 = java.net.URLClassLoader@1e81f4dc
url2 = java.net.URLClassLoader@4d591d15
 Same? false
fractionClass1 = class org.apache.commons.lang3.math.Fraction
fractionClass2 = class org.apache.commons.lang3.math.Fraction
 Same? false
oneHalf1 = 1/2
oneHalf2 = 1/2
 Same? false
 类似资料:
  • 我有一个,它从

  • 我曾经读到过Java中类装入器的委托模型的“唯一性”特性: https://www.baeldung.com/java-classloaders#uniqueness 我不明白,如果没有这样的模型,我们怎么会有加载非唯一类的风险呢? 当类装入器使用完全限定的类名来装入它们时,我们如何才能最终装入重复的类,特别是当我们在将任务委托给父装入器之前检查一个类是否已经装入时? https://www.ba

  • 我想找到或创建一个仅加载系统类的 Java 类装入器,不包括应用程序定义的类路径上的任何类。我的目标是使用该类装入器来构建一个从特定 JAR 文件装入的类装入器,使用仅系统类装入器解析系统类,但不会用我的应用程序定义的任何类污染 JAR 文件中的类。 到目前为止,我还没有找到任何方法来创建一个不使用私有API或对Java实现进行假设的仅系统类加载器。请参阅下面的代码,该代码适用于我当前的环境,但会

  • 我有一个问题,看起来它是因为同时使用了类加载器的两个实例而引起的。计划任务总是运行两次而不是一次,即使设置为避免并发使用。 我如何在运行时唯一地识别给定类实例的类装入器实例?我知道它的完全限定名是类加载器、包和类名的组合。我想知道同一个类装入器的两个实例是否同时运行。 我尝试使用以下日志记录,但它没有给我任何有用的方面,我实际上希望看到什么(相当于一个唯一的线程id等)。是的,它确实给出了类加载器

  • rank ▲ ✰ vote url 3 1346 1485 2648 url Python中如何在一个函数中加入多个装饰器? 怎么做才能让一个函数同时用两个装饰器,像下面这样: @makebold @makeitalic def say(): return "Hello" 我希望得到 <b><i>Hello</i></b> 我只是想知道装饰器怎么工作的! 去看看文档,答在下面: def

  • 问题内容: 假设,我运行一个API,并且当用户在用户资源上发出GET请求时,我将以JSON的形式返回相关字段 如您所见,User中的Secret字段具有。这意味着在大多数操作中,我都不想返回。在这种情况下,响应将是 忽略该字段将不会返回该字段机密。 现在,我将打开一个我想返回秘密字段的管理员专用路由。但是,这将意味着复制User结构。 我当前的解决方案如下所示: 有没有一种方法可以将User嵌入a