Java 中的静态/实例初始化程序块按什么顺序运行?
假设一个项目包含多个类,每个类都有一个静态初始化块。这些块按什么顺序运行?我知道在一个类中,这些块按照它们在代码中出现的顺序运行。我读到它在各个类中都是相同的,但我编写的一些示例代码与此不同。我使用了这段代码:
package pkg;
public class LoadTest {
public static void main(String[] args) {
System.out.println("START");
new Child();
System.out.println("END");
}
}
class Parent extends Grandparent {
// Instance init block
{
System.out.println("instance - parent");
}
// Constructor
public Parent() {
System.out.println("constructor - parent");
}
// Static init block
static {
System.out.println("static - parent");
}
}
class Grandparent {
// Static init block
static {
System.out.println("static - grandparent");
}
// Instance init block
{
System.out.println("instance - grandparent");
}
// Constructor
public Grandparent() {
System.out.println("constructor - grandparent");
}
}
class Child extends Parent {
// Constructor
public Child() {
System.out.println("constructor - child");
}
// Static init block
static {
System.out.println("static - child");
}
// Instance init block
{
System.out.println("instance - child");
}
}
并得到了这个输出:
开始
静态 - 祖父母
静态 - 父级
静态 - 子
实例 - 祖父母
构造函数 - 祖父母
实例 - 父级
构造函数 - 父级
实例 - 子
构造函数 - 子
结束
的答案是,父母的块在孩子的块之前运行,但这可能只是巧合,如果两个类不在同一层次结构中,则没有帮助。
编辑:
我通过将其附加到 LoadTest.java 来修改我的示例代码:
class IAmAClassThatIsNeverUsed {
// Constructor
public IAmAClassThatIsNeverUsed() {
System.out.println("constructor - IAACTINU");
}
// Instance init block
{
System.out.println("instance - IAACTINU");
}
// Static init block
static {
System.out.println("static - IAACTINU");
}
}
正如类名称所暗示的那样,我从未在任何地方引用过新类。新程序产生与旧程序相同的输出。
Say a project contains several classes, each of which has a static initializer block. In what order do those blocks run? I know that within a class, such blocks are run in the order they appear in the code. I've read that it's the same across classes, but some sample code I wrote disagrees with that. I used this code:
package pkg;
public class LoadTest {
public static void main(String[] args) {
System.out.println("START");
new Child();
System.out.println("END");
}
}
class Parent extends Grandparent {
// Instance init block
{
System.out.println("instance - parent");
}
// Constructor
public Parent() {
System.out.println("constructor - parent");
}
// Static init block
static {
System.out.println("static - parent");
}
}
class Grandparent {
// Static init block
static {
System.out.println("static - grandparent");
}
// Instance init block
{
System.out.println("instance - grandparent");
}
// Constructor
public Grandparent() {
System.out.println("constructor - grandparent");
}
}
class Child extends Parent {
// Constructor
public Child() {
System.out.println("constructor - child");
}
// Static init block
static {
System.out.println("static - child");
}
// Instance init block
{
System.out.println("instance - child");
}
}
and got this output:
START
static - grandparent
static - parent
static - child
instance - grandparent
constructor - grandparent
instance - parent
constructor - parent
instance - child
constructor - child
END
The obvious answer from that is that parents' blocks run before their children's, but that could just be a coincidence and doesn't help if two classes aren't in the same hierarchy.
EDIT:
I modified my example code by appending this to LoadTest.java:
class IAmAClassThatIsNeverUsed {
// Constructor
public IAmAClassThatIsNeverUsed() {
System.out.println("constructor - IAACTINU");
}
// Instance init block
{
System.out.println("instance - IAACTINU");
}
// Static init block
static {
System.out.println("static - IAACTINU");
}
}
As implied by the class name, I never referenced the new class anywhere. The new program produced the same output as the old one.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
请参阅 JLS 版本的第 12.4 和 12.5 节8,他们详细介绍了所有这些(12.4 为静态变量,12.5 为实例变量)。
对于静态初始化(第 12.4 节):
类或接口类型 T 将在第一次出现以下任一情况之前立即进行初始化:
(以及一些狡猾的词句)
See section 12.4 and 12.5 of the JLS version 8, they go into gory detail about all of this (12.4 for static and 12.5 for instance variables).
For static initialization (section 12.4):
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
(and several weasel-word clauses)
首次访问类时,类的静态初始化程序将运行,以创建实例或访问静态方法或字段。
因此,对于多个类,这完全取决于运行来导致加载这些类的代码。
The static initializer for a class gets run when the class is first accessed, either to create an instance, or to access a static method or field.
So, for multiple classes, this totally depends on the code that's run to cause those classes to get loaded.
基思和克里斯的答案都很好,我只是为我的具体问题添加一些更多细节。
静态初始化块按照其类初始化的顺序运行。那么,那是什么顺序呢?根据 JLS 12.4.1:
为了说明这一点,以下是示例中发生的情况的演练:
Keith's and Chris's answers are both great, I'm just adding some more detail for my specific question.
Static init blocks run in the order in which their classes are initialized. So, what order is that? Per JLS 12.4.1:
To illustrate, here's a walkthrough of what's happening in the example:
有一种情况不会调用静态块。
上面的代码输出
10
来自“编辑器”的更新
对此的技术解释位于 JLS 12.4.1
直观的解释是
Super.i
和Sub.i
实际上是同一个变量,而Sub
中什么都没有> 实际上需要初始化 Super.i 才能获得正确的值。(如果
Super.i
的初始化表达式引用Sub
类,情况会有所不同。但是这样你就会在初始化顺序中出现一个循环。仔细观察阅读 JLS 12.4.1 和 JLS 12.4.2 解释说这是允许的,并允许您准确地计算出实践中会发生什么。)There is one case in which a static block will not be called.
The above code outputs
10
Update from an "editor"
The technical explanation for this is in JLS 12.4.1
The intuitive explanation is
Super.i
andSub.i
are actually the same variable, and nothing inSub
actually needs to be initialized for theSuper.i
to get the correct value.(It would be different if the initialization expression for
Super.i
referred to theSub
class. But then you would have a cycle in the initialization order. A careful reading of JLS 12.4.1 and JLS 12.4.2 explains that this is allowed, and allows you to work out exactly what would happen in practice.)类的初始化包括执行其静态初始化程序和类中声明的静态字段(类变量)的初始化程序。
接口的初始化包括执行接口中声明的字段(常量)的初始化程序。
在初始化类之前,必须初始化其直接超类,但不初始化该类实现的接口。同样,接口初始化之前不会初始化接口的超级接口。
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
Initialization of an interface consists of executing the initializers for fields (constants) declared in the interface.
Before a class is initialized, its direct superclass must be initialized, but interfaces implemented by the class are not initialized. Similarly, the superinterfaces of an interface are not initialized before the interface is initialized.
您可以在同一个类中拥有多个静态和实例初始化程序,因此
每个都像单个块一样执行。
You can have multiple static and instance initializers in the same class, therefore
Each is executed as if it was a single block.
注释中的数字表示评估顺序,越小越早。
如示例所示,
Numbers in the comment indicate the evaluation order, the smaller, the earlier.
As the example showed,
http://docs.oracle.com/javase/tutorial/java/javaOO /initial.html
请检查java文档。
然后明确提到,无论静态块有多少,它们都会按照它们出现的顺序作为单个块执行,
所以,
我的理解是java正在将您的代码视为
static int i;
这就是为什么你得到输出 2
希望这有帮助
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
kindly check java documentation.
then clearly mentioned no matter how may static blocks are there they will be executed as a single block in the order they appear
So,
My understanding here is java is looking your code as
static int i;
that is why you are getting output 2
hope this is helpful