什么是初始化块?

我们可以把代码放在构造函数或方法或初始化块中。 什么是初始化块的使用? 每个Java程序都必须拥有它吗?

首先,有两种types的初始化块 :

  • 实例初始化块 ,和
  • 静态初始化块

这段代码应该说明它们的用法以及它们执行的顺序:

public class Test { static int staticVariable; int nonStaticVariable; // Static initialization block: // Runs once (when the class is initialized) static { System.out.println("Static initalization."); staticVariable = 5; } // Instance initialization block: // Runs each time you instantiate an object { System.out.println("Instance initialization."); nonStaticVariable = 7; } public Test() { System.out.println("Constructor."); } public static void main(String[] args) { new Test(); new Test(); } } 

打印:

 Static initalization. Instance initialization. Constructor. Instance initialization. Constructor. 

如果您希望运行某些代码,而不考虑使用哪个构造函数,或者想要为匿名类执行一些实例初始化,则实例itialization块很有用。

想添加到@ aioobe的答案

执行顺序:

  1. 超类的静态初始化块

  2. 类的静态初始化块

  3. 超类的实例初始化块

  4. 超级类的构造函数

  5. 类的实例初始化块

  6. 类的构造函数。

要记住一些其他的要点(点1是@ aioobe的回答):

  1. 静态初始化块中的代码将在类加载时执行(是的,这意味着每个类加载只有一次),在构造类的任何实例之前和调用任何静态方法之前。

  2. 实例初始化块实际上被Java编译器复制到类的每个构造函数中。 所以每次实例初始化块中的代码都在构造函数中的代码之前执行。

通过添加更多点的aioobe很好的答案

 public class StaticTest extends parent { static { System.out.println("inside satic block"); } StaticTest() { System.out.println("inside constructor of child"); } { System.out.println("inside initialization block"); } public static void main(String[] args) { new StaticTest(); new StaticTest(); System.out.println("inside main"); } } class parent { static { System.out.println("inside parent Static block"); } { System.out.println("inside parent initialisation block"); } parent() { System.out.println("inside parent constructor"); } } 

这给了

 inside parent Static block inside satic block inside parent initialisation block inside parent constructor inside initialization block inside constructor of child inside parent initialisation block inside parent constructor inside initialization block inside constructor of child inside main 

它像是说明显但似乎更清楚一点。

示例代码在这里被认可为答案是正确的,但我不同意它。 它没有显示发生了什么事情,我将向您展示一个很好的例子来理解JVM的实际工作方式:

 package test; class A { A() { print(); } void print() { System.out.println("A"); } } class B extends A { static int staticVariable2 = 123456; static int staticVariable; static { System.out.println(staticVariable2); System.out.println("Static Initialization block"); staticVariable = Math.round(3.5f); } int instanceVariable; { System.out.println("Initialization block"); instanceVariable = Math.round(3.5f); staticVariable = Math.round(3.5f); } B() { System.out.println("Constructor"); } public static void main(String[] args) { A a = new B(); a.print(); System.out.println("main"); } void print() { System.out.println(instanceVariable); } static void somethingElse() { System.out.println("Static method"); } } 

在开始评论源代码之前,我会给你一个类的静态variables的简短解释:

首先是它们被称为类variables,它们属于类而不是类的特定实例。 该类的所有实例共享此静态(类)variables。 每个variables都有一个默认值,取决于原始types或引用types。 另一件事情是当你在类的某些成员(初始化块,构造函数,方法,属性)中重新分配静态variables,并且这样做时,你正在改变静态variables的值而不是特定的实例,你正在改变它实例。 总结静态部分我会说,一个类的静态variables是不是当你首次实例化类的时候创build的,它们是在你定义你的类时创build的,它们存在于JVM中而不需要任何实例。 因此,从外部类(它们没有定义的类)中静态成员的正确访问是通过使用类名<CLASS_NAME>.<STATIC_VARIABLE_NAME>点,然后是要访问的静态成员(模板: <CLASS_NAME>.<STATIC_VARIABLE_NAME> ) 。

现在让我们看看上面的代码:

入口点是主要的方法 – 只有三行代码。 我想参考当前批准的例子。 根据它,打印“静态初始化块”之后必须打印的第一件事是“初始化块”,这里是我的不同意见,非静态初始化块不在构造函数之前调用,它在构造函数的任何初始化之前调用在其中定义了初始化块的类。 当你创build一个对象(类的实例)时,类的构造函数是第一件事,然后当你input构造函数时,第一个被调用的部分是隐式(默认)超级构造函数或显式超级构造函数,或者显式调用另一个被重载构造函数(但在某些情况下,如果有一个重载的构造函数的链,最后一个隐式或显式地调用超级构造函数)。

有一个对象的多态创build,但在进入B类及其主要方法之前,JVM初始化所有类(静态)variables,然后通过静态初始化块(如果存在的话),然后进入B类,并以执行主要方法。 然后立即(隐式地)调用类B的构造函数,使用多态性,类A的构造函数体中调用的方法(重写方法)是在类B中定义的方法,在这种情况下在重新初始化之前使用名为instanceVariable的variables。 在closuresB类的构造函数之后,线程返回到B类的构造函数,但在打印“构造函数”之前,首先进入非静态初始化块。 为了更好地理解用一些IDEdebugging它,我更喜欢Eclipse。

初始化块包含创build实例时始终执行的代码。 它用来声明/初始化一个类的各种构造函数的公共部分。

初始化构造函数和初始化块的顺序无关紧要,初始化块始终在构造函数之前执行。

如果我们想为一个类的所有对象执行一次代码呢?

我们在Java中使用静态块。

初始化块在类被初始化和调用构造函数之前执行。 它们通常放在大括号内的构造函数之上。 将它们包含在你的课堂中是没有必要的。

它们通常用于初始化引用variables。 这个页面给了一个很好的解释

这个问题并不完全清楚,但下面简要介绍一下您可以在对象中初始化数据的方式。 假设您有一个包含对象列表的类A,

1)将初始值放在字段声明中:

 class A { private List<Object> data = new ArrayList<Object>(); } 

2)在构造函数中分配初始值:

 class A { private List<Object> data; public A() { data = new ArrayList<Object>(); } } 

这些都假设你不想传递“数据”作为构造函数的参数。

如果将重载的构造函数与上面的内部数据混合在一起,事情会变得棘手。 考虑:

 class B { private List<Object> data; private String name; private String userFriendlyName; public B() { data = new ArrayList<Object>(); name = "Default name"; userFriendlyName = "Default user friendly name"; } public B(String name) { data = new ArrayList<Object>(); this.name = name; userFriendlyName = name; } public B(String name, String userFriendlyName) { data = new ArrayList<Object>(); this.name = name; this.userFriendlyName = userFriendlyName; } } 

请注意,有很多重复的代码。 你可以通过让构造函数相互调用来解决这个问题,或者你可以有一个每个构造函数调用的私有初始化方法:

 class B { private List<Object> data; private String name; private String userFriendlyName; public B() { this("Default name", "Default user friendly name"); } public B(String name) { this(name, name); } public B(String name, String userFriendlyName) { data = new ArrayList<Object>(); this.name = name; this.userFriendlyName = userFriendlyName; } } 

要么

 class B { private List<Object> data; private String name; private String userFriendlyName; public B() { init("Default name", "Default user friendly name"); } public B(String name) { init(name, name); } public B(String name, String userFriendlyName) { init(name, userFriendlyName); } private void init(String _name, String _userFriendlyName) { data = new ArrayList<Object>(); this.name = name; this.userFriendlyName = userFriendlyName; } } 

这两个(或多或less)是相同的。

我希望这给你一些关于如何初始化对象中的数据的提示。 我不会谈论静态初始化块,因为目前可能有点进步。

编辑:我已经解释了你的问题是“如何初始化我的实例variables”,而不是“初始化块如何工作”作为初始化块是一个相对先进的概念,从你问的问题的语气更简单的概念。 我可能是错的。

要知道静态初始化块的使用,请参阅Class.forName源代码也是这篇文章的用处http://cephas.net/blog/2005/07/31/java-classfornamestring-classname-and-jdbc/ ,它们使用初始化块进行dynamic类加载。

 public class StaticInitializationBlock { static int staticVariable; int instanceVariable; // Static Initialization Block static { System.out.println("Static block"); staticVariable = 5; } // Instance Initialization Block { instanceVariable = 7; System.out.println("Instance Block"); System.out.println(staticVariable); System.out.println(instanceVariable); staticVariable = 10; } public StaticInitializationBlock() { System.out.println("Constructor"); } public static void main(String[] args) { new StaticInitializationBlock(); new StaticInitializationBlock(); } } 

输出:

 Static block Instance Block 5 7 Constructor Instance Block 10 7 Constructor 

初始化块在类中定义,而不是作为方法的一部分。 它为每个为类创build的对象执行。 在下面的例子中, Employee类定义了一个初始化块:

 class Employee { { System.out.println("Employee:initializer"); } }