Java 没有初始化就不能执行静态块

Java 没有初始化就不能执行静态块,java,static-block,Java,Static Block,我有一个关于静态块的问题: 假设我有一门课看起来像这样: class SomeClass { static { System.out.println("static block"); } } 我在某处定义了一个SomeClass类型的变量 public static void main(String args[]) { SomeClass foo; } 现在我以为静态块会被执行,但事实并非如此。据我所知,静态块在类加载器加载SomeClass类时立即执

我有一个关于静态块的问题:

假设我有一门课看起来像这样:

class SomeClass {
    static {
        System.out.println("static block");
    }
}
我在某处定义了一个
SomeClass
类型的变量

public static void main(String args[]) {
    SomeClass foo;
}
现在我以为静态块会被执行,但事实并非如此。据我所知,静态块在类加载器加载
SomeClass
类时立即执行。现在谈谈我真正的问题:

不是在我定义了该类型的变量后就加载了类吗?。如果是,为什么不执行静态块

如果答案应该是“否”,那么我如何知道类加载器是否已经加载了一个类,以及加载该类的不同可能性(我知道2:初始化变量&使用静态字段/方法)

请参阅本文档:

那么什么时候加载类呢?有两种情况:执行新字节码时(例如,FooClass f=new FooClass();),以及字节码对类进行静态引用时(例如,System.out)

在您的示例中,
SomeClass-foo
既不执行SomeClass的字节码,也不对SomeClass进行静态引用。这就是类未加载的原因

因此,按照您的示例,在类中添加一个静态字段

public class SomeClass {
    static {
        System.out.println("static block");
    }

    static String abc = "abc";
}
SomeClass加载在以下任一位置:

SomeClass foo = new SomeClass();

当我定义了一个这种类型的变量时,类不是被加载了吗

是的,它是loaded1,但不会由于声明变量而初始化它。但是,当您创建该类型的实例或访问该类型的静态字段时,这足以触发初始化,包括执行静态块

请参阅这个相关的Q&A,它列出了所有可以触发初始化的事情


我如何知道类加载器是否已经加载了一个类,以及加载该类的不同可能性(我知道2:初始化变量&使用静态字段/方法)

我能想到的确定类何时加载(与初始化不同)的唯一方法是:

  • 打开JVM的类加载器消息(使用
    -verbose:class
    ),或

  • 使用一个客户类加载器,当它看到加载类的请求时,会注意并执行适当的操作

实际上要加载一个类:

  • 使用
    Class.forName
    或类似工具显式加载时,或直接调用类加载器时

  • 当需要加载它以链接另一个类时,或

  • 在JVM启动时,如果该类被命名为入口点类

中指定了加载/链接/初始化步骤



1-事实上,
SomeClass
需要在链接包含该
main
方法的类的同时加载;i、 e.在调用包含该局部声明的方法之前。

编译器可以删除foo,在本例中是SomeClass的导入
Class.forName(“…SomeClass”)
会初始化该类。@JoopEggen啊,好的,但是编译器不能在foo被初始化但从未使用时也删除它吗?或者编译器永远不会这样做?编译器(和运行时)通常会在需要类之前延迟加载类。导入语句是编译器的指令,但不会在运行时执行。我见过这样的环境:只有在执行引用该类的方法时才加载该类,而在执行其他不引用该类的方法时才加载该类。class.forName使用布尔参数重载以初始化该类;默认情况下为true。初始化变量可能足以调用类加载和初始化,即使整个对象已优化。应该考虑到(理想地)有不止一个java编译器。@ ParkerHalo是的。简单的编译器不会删除未使用的变量。Ermm。。。。
SomeClass
类已>>加载
System.out.println(SomeClass.abc);