假设我有两个班级A和B。
class A{}
import A;
class B{}
然后,如果在我用main
方法if(object instanceof B)
处理的某个对象上,它将加载类A
以及类B
的import语句中吗?
类加载器究竟何时会在运行时加载这些类?
答案 0 :(得分:5)
有两件事要注意:
import
语句不会影响类的运行时行为。不会为import语句生成任何代码。而且,如果您仅将B类中的A类导入,则加载B类不会导致加载A类。
类加载时间和类初始化时间不同。
类的生命周期是在使用类之前对其进行加载,链接和初始化(请参见JLS Chapter 12)。
加载由类加载器执行,涉及查找类文件,将其读取到byte[]
中并调用ClassLoader::defineClass
。
链接是由JVM核心代码执行的,包括验证,准备和解析符号引用。 JLS 12.3说:
该规范为实现链接活动(以及由于递归,加载)发生的时间提供了实现上的灵活性,前提是尊重Java编程语言的语义,并且在其之前对类或接口进行了完整的验证和准备初始化,并且在链接期间检测到的错误被抛出到程序中某个位置,在该位置,程序采取了一些可能需要链接到错误所涉及的类或接口的操作。
这意味着我们无法确定何时执行不同的任务。
所有相关类均已链接之后,才会进行初始化。根据{{3}}:
类或接口类型T将在以下任何一种首次出现之前立即初始化:
- T是一个类,并创建T的实例。
- 调用T声明的静态方法。
- 分配了由T声明的静态字段。
- 使用由T声明的静态字段,并且该字段不是常量变量(第4.12.4节)。
根据JLS(请参见上文),我们无法确切说明何时B
将被加载和链接。我们可以说的是,它发生在B
初始化之前……如果已初始化。 (您可以通过打开一些JVM日志记录来了解类加载的顺序。但是,顺序可能会因JVM供应商和版本而异。)
根据JLS(请参见上文),B
的初始化(通常)是在B
方法中创建main
的第一个实例时发生的。假设您问题中的object
已初始化为B
实例,则初始化将在instanceof
测试之前进行。如果没有,则B
测试不会初始化instanceof
。
表面上,不需要加载类A
。 (这取决于类B
是否实际使用以及如何实际使用类A
,以及代码库的其他部分是否/如何使用A
。)
答案 1 :(得分:0)
您可以通过以下方式进行测试:
Main.java:
package test;
import test.sub.B;
public class Main {
public static void main(String args[]) {
System.out.println("Creating object");
final B b = new B();
System.out.println("instanceof check");
if (b instanceof B) {
// Do nothing
}
}
}
A.java:
package test;
public class A {
static {
System.out.println("Class A loaded");
}
}
B.java:
package test.sub;
import test.A;
public class B {
A a;
static {
System.out.println("Class B loaded");
}
}
输出:
Creating object
Class B loaded
instanceof check
因此,导入和声明(A a;
)都不会加载类。
这符合维基百科的声明:The Java Class Loader [...] dynamically loads Java classes [...]. [...] This loading is typically done "on demand", in that it does not occur until the class is called by the program. [...]
当您将类A a;
中的B
更改为A a = new A();
时,将加载类A
。