gpt4 book ai didi

java - 如果从不使用相应的类,类加载器是否会加载类文件?

转载 作者:行者123 更新时间:2023-12-05 01:04:49 25 4
gpt4 key购买 nike

为了让我的问题更清楚,请考虑以下用例:

假设有一个包允许在给定平台上进行一组操作,例如在 Windows 上编辑注册表的类。这个包在其他平台上不存在,因为在其他操作系统上没有等效的操作。

为了简单起见,考虑

windows/Registry.java

package windows;

public class Registry {

static Registry instance = null;
static{
System.out.println("print from static block");
}

private Registry() {
System.out.println("Registry instance created!");
}

public static synchronized Registry getInstance() {
if (null == instance) {
instance = new Registry();
}
return instance;
}

public void foo() {
System.out.println("foo called.");
}
}

以及我将有条件地使用注册表的类:main/Main.java

package main;

import windows.Registry;

public class Main {

public static void test1(boolean onWindows) {
if (onWindows) {
Registry instance = Registry.getInstance();
System.out.println("We are on Windows: ");
instance.foo();
} else {
System.out.println("We are somewhere else!");
}
}

public static void main(String[] args) {
System.out.println("Entered main");
boolean onWindows = args.length > 0 ? Boolean.parseBoolean(args[0]) : false;
test1(onWindows);
}
}

问题是,如果Main.class中没有明确执行函数或类,是否保证Registry.class中的代码不会被执行?

我能够在多个桌面平台和不同的 java 版本上测试此示例,但我想知道是否记录了此行为并且可以依赖它,是否因此在其他平台上也是预期的行为,例如JRE 的 android 或嵌入式版本。

如果没有这样的保证,因为(可能是自定义的)类加载器可能决定加载类路径中的所有 .class 文件,我可以假设代码在没有 的情况下也可以工作java.lang.NoClassDefFoundError 如果 onWindows 为假并且我从类路径中删除 Registry.class

到目前为止我观察到的行为是

rm -rf bld; mkdir bld && javac -d bld src/windows/Registry.java src/main/Main.java && java -classpath bld main.Main true
Entered main
print from static block
Registry instance created!
We are on Windows:
foo called.

rm -rf bld; mkdir bld && javac -d bld src/windows/Registry.java src/main/Main.java && java -classpath bld main.Main false
Entered main
We are somewhere else!


rm -rf bld; mkdir bld && javac -d bld src/windows/Registry.java src/main/Main.java && rm -r bld/windows && java -classpath bld main.Main false
Entered main
We are somewhere else!

rm -rf bld; mkdir bld && javac -d bld src/windows/Registry.java src/main/Main.java && rm -r bld/windows && java -classpath bld main.Main true
Entered main
Exception in thread "main" java.lang.NoClassDefFoundError: windows/Registry
at main.Main.test1(Main.java:9)
at main.Main.main(Main.java:20)
Caused by: java.lang.ClassNotFoundException: windows.Registry
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 2 more

是否定义了这些行为(惰性类加载器和删除 Registry.class)?

最佳答案

The question is, if no function or class is explicitly executed in Main.class, is it guaranteed that no code from Registry.class is executed?

这并不直接涉及类加载,而是涉及类初始化,这是相关类中的任何代码被执行的第一个点。具体来说,在这个阶段执行静态初始化 block 和静态成员的初始化器。有问题的类此时必须已经加载和验证,但它可能已经加载了任意时间。

根据 JLS 12.4.1 ,

A class or interface T will be initialized immediately before thefirst occurrence of any one of the following:

  • T is a class and an instance of T is created.

  • A static method declared by T is invoked.

  • A static field declared by T is assigned.

  • A static field declared by T is used and the field is not a constant variable

因此,如果您从不实例化该类或访问它的任何静态方法或字段(读取作为“常量变量”的静态字段除外),则不会执行该类中的任何代码。

但是一个类没有被初始化并不意味着不会尝试加载它。 JLS 不禁止实现预先加载类。事实上,JLS 12.2.1具体来说:

a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together.

因此,不,依靠您的类 main.Main 表示的应用程序在没有 java.lang.NoClassDefFoundError 或其他加载错误的情况下运行是不安全的当类 windows.Registry 无法加载时,无论是否可以预期实际使用。但是,您可以在适当的情况下依赖未初始化的类,因此不会执行其中的任何代码。

关于java - 如果从不使用相应的类,类加载器是否会加载类文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71356282/

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