Java 关于类加载的困惑

Java 关于类加载的困惑,java,Java,我对JVM实际加载类的时间有点困惑。我注意到类加载器将在引用类时加载该类 我正在使用java6环境并使用-verbose:class运行以跟踪类加载。 例如: MyObject obj = new MyObject(); //MyObject.class will be loaded 然而,在这种情况下 // ClassC.java package com.gogog22510.test; public class ClassC {} // ClassB.java package com.g

我对JVM实际加载类的时间有点困惑。我注意到类加载器将在引用类时加载该类

我正在使用java6环境并使用-verbose:class运行以跟踪类加载。 例如:

MyObject obj = new MyObject(); //MyObject.class will be loaded
然而,在这种情况下

// ClassC.java
package com.gogog22510.test;
public class ClassC {}

// ClassB.java
package com.gogog22510.test;
public class ClassB extends ClassC {}

// ClassA.java
package com.gogog22510.test;
public class ClassA {
    public ClassC test() {
        return new ClassB();
    }
}
当我的测试程序初始化ClassA时,它将加载所有ClassA、ClassB和ClassC,即使我没有调用test()

控制台:

[已从文件加载TestClassLoad:/…/bin/]
开始加载ClassA
[已从文件加载ClassA:/C:/…/bin/]
[已从文件加载ClassC:/C:/…/bin/]
[已从文件加载ClassB:/C:/…/bin/]

但是如果我像这样更改test()方法的返回类型:

// ClassA.java
package com.gogog22510.test;
public class ClassA {
    public ClassB test() {
        return new ClassB();
    }
}
除非调用test()方法,否则ClassLoader将只将ClassA加载到perm空间

控制台:

[已从文件加载TestClassLoad:/…/bin/]
开始加载ClassA
[已从文件加载ClassA:/C:/…/bin/]


为什么类加载器在我显式调用方法之前加载所有三个类?

我认为这发生在验证步骤中,以确保
ClassC
ClassB
的子类,以便验证返回类型

,他们说:

如果该方法返回引用类型,则必须使用areturn返回 指令,并且返回值的类型必须为赋值 兼容(JLS§5.2)的返回描述符(§4.3.3) 方法

另见:

验证(§4.10)确保类的二进制表示 或接口结构正确(§4.9)。验证可能导致 需要加载的附加类和接口(§5.3),但不需要 使其得到验证或准备


它将加载所有的ClassA、ClassB和ClassC,你怎么知道呢?我不能重现这种行为,只有ClassA被加载@TheLostMind是的,你是对的。类的加载和初始化是两个过程,但由于它们密切相关,人们倾向于将它们命名为相同的过程,我(可能错误地)认为OP也可能意味着初始化。我发表评论的目的是鼓励OP添加更多关于其代码以及他如何确定类已加载的详细信息。@LostMind我还不能100%确定这些来自JLS的代码片段的相关性。@LostMind是的,但我想从OP那里听到,只是为了确保这是一个真正的问题,而不是某种误解:)是的,就是这样。JVM需要加载ClassA,这包括将方法代码加载到内存中;ClassA有一个返回ClassC的方法,因此,它加载ClassC;最后,该方法返回ClassB的对象,因此也需要加载ClassB。不管是否调用该方法,在调用该方法之前,该方法需要已经加载到内存中,因此类加载器加载每个方法需要工作的所有内容。例如,如果他有另一个返回ClassD的方法,那么这两个方法都必须可用,并且ClassD也必须被加载。@Sekkuar我认为在方法返回期间进行类型转换时会发生这种情况。它将完成文章中提到的验证,并要求ClassB和ClassC在ClassLoader中准备就绪。@Vlad我之前只查看了文章的链接和加载部分,没有看到该部分tho…感谢您的回答:)
// ClassA.java
package com.gogog22510.test;
public class ClassA {
    public ClassB test() {
        return new ClassB();
    }
}