gpt4 book ai didi

java - 如果未访问类,是否保证 static init 不运行?

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:16:38 24 4
gpt4 key购买 nike

我知道有很多关于此的主题和资源,但我想知道一个非常具体的问题(检查所有来源以获得明确答案可能需要很长时间)。

我知道 JVM/Dalvik 保证当您访问类的静态字段时(final static 原始值除外),该类的静态字段已经初始化。反之亦然吗?如果我从不根本访问一个类(例如,因为另一个静态方法中的switch-case代码永远不会到达某个分支),是否可以保证 VM 初始化这个类的静态?

假设我有这样一个类:

public class Boo {
public static int[] anything = new int[] { 2,3,4 };
private static int[] something = new int[] { 5,6,7 }; // this may be much bigger as well

public static final int[] getAndClear() {
int[] st = something;
something = null;
return st;
}
}

我的应用程序是一个非常特殊的应用程序(在某些方面并不典型),它可能包含数百个类,例如 Boo(由代码生成器生成),其中 something 可能是一个包含不同元素数的数组(因此它有时也可能包含很多元素)。

根据应用程序输入,许多这些预生成的类可能永远无法访问。我不希望大量 int[] 对象被不必要地初始化,占用大量内存。

最佳答案

I know that JVM/Dalvik guarantees that by the time you access a static field of a class (except for final static primitive values), the static fields of the class are already initialized.

这大部分是正确的,但由于常量内联,某些静态字段并非如此。在

class A {
public static final String FOO = "foo";

static { System.out.println("loaded A"); }
}

public class B {
public static void main(String... argv) {
System.out.println("Got " + A.FOO);
}
}

JVM 将打印“Got foo”但不会打印“loaded A”。事实上,即使 A.class B 也会运行不在类路径上,但至少是 A.java 之一或 A.class编译时必须可用 B.java .


Is the opposite true as well? If I never access a class at all (e.g. because the switch-case code in another static method never reaches a certain branch), is it guaranteed that the VM does not initialize statics of this class?

是的。 JLS 规定了发生类加载和初始化的确切条件,因此 JVM 实现没有自由地急切加载或初始化类。

12.4.1是感兴趣的章节。

12.4.1. When Initialization Occurs

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

  1. T is a class and an instance of T is created.
  2. T is a class and a static method declared by T is invoked.
  3. A static field declared by T is assigned.
  4. A static field declared by T is used and the field is not a constant variable (§4.12.4).
  5. T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

“紧接之前”的措辞禁止任何急切,并规定当两个类都尝试执行上述操作之一时会发生什么——有一个锁与一个已加载但未初始化的类相关联,并且都等待直到线程首先获取该锁执行初始化。

“并且该字段不是常量变量 (§4.12.4)”的措辞是我在 class B 中说明的规则的异常(exception)。使用 A.FOO以上。


public static final int[] getAndClear() { ... }

应该是synchronized因为否则两个线程可能都获得相同的数组而不是一个接收 null .我上面提到的类加载器锁不保护 getAndClear .

关于java - 如果未访问类,是否保证 static init 不运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13092132/

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