什么是初始化块?

时间:2010-10-21 12:28:54

标签: java constructor initialization initialization-block

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

11 个答案:

答案 0 :(得分:163)

首先,initialization blocks有两种类型:

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

此代码应说明它们的使用以及它们的执行顺序:

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块非常有用。

答案 1 :(得分:89)

想加入@ aioobe的回答

执行顺序:

  1. 超类的静态初始化块

  2. 类的静态初始化块

  3. 超类的实例初始化块

  4. 超类的构造函数

  5. 类的实例初始化块

  6. 班级的构造函数。

  7. 要记住几点要点(第1点是@ aioobe的回答重申):

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

    2. 实例初始化块实际上由Java编译器复制到该类具有的每个构造函数中。因此,每次实例初始化块中的代码在构造函数中的代码之前执行完全

答案 2 :(得分:6)

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

它表示明显但似乎更清楚。

答案 3 :(得分:3)

示例代码在此处被批准作为答案是正确的,但我不同意它。它没有显示正在发生的事情,我将向您展示一个很好的例子来了解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");
        }
    }

在开始评论源代码之前,我将简要介绍一个类的静态变量:

首先,它们被称为类变量,它们属于类而不是类的特定实例。该类的所有实例共享此静态(类)变量。每个变量都有一个默认值,具体取决于原始类型或引用类型。另一件事是当您在类的某些成员中重新分配静态变量(初始化块,构造函数,方法,属性)并且这样做时您要更改静态变量的值而不是特定实例,您要为所有实例更改它实例。为了得出静态部分,我将说明类的静态变量不是在第一次实例化类时创建的,它们是在定义类时创建的,它们存在于JVM中而不需要任何实例。因此,从外部类(未定义它们的类)中正确访问静态成员的方法是使用后跟dot的类名,然后使用要访问的静态成员(模板:<CLASS_NAME>.<STATIC_VARIABLE_NAME>)。 / p>

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

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

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

答案 4 :(得分:1)

初始化程序块包含每当创建实例时始终执行的代码。它用于声明/初始化类的各种构造函数的公共部分。

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

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

我们在Java中使用Static Block。

答案 5 :(得分:0)

只要初始化类并且在调用构造函数之前,就会执行初始化块。它们通常位于大括号内的构造函数上方。完全没有必要将它们包含在您的课程中。

它们通常用于初始化引用变量。这个page提供了一个很好的解释

答案 6 :(得分:0)

问题并不完全清楚,但这里简要介绍了如何初始化对象中的数据。假设你有一个包含对象列表的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;
    }
}

这两者是(或多或少)等价的。

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

编辑:我将你的问题解释为“我如何初始化我的实例变量”,而不是“初始化块如何工作”,因为初始化块是一个相对先进的概念,从问题的基调来看,你似乎是'重新询问更简单的概念。我错了。

答案 7 :(得分:0)

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

答案 8 :(得分:0)

Initialism以较小的字体大小显示<abbr>元素内的文本

答案 9 :(得分:0)

只需添加 @aioobe @Biman Tripathy 的出色答案即可。

静态初始值设定项与静态上下文中的构造函数等效。这是设置静态环境所必需的。 实例初始化器最适合匿名内部类。

  • 在类中也可能有多个初始化程序块
  • 当我们有多个初始化程序块时,它们按照出现的顺序执行(实际上是由JVM复制到构造函数中的)
  • 初始化程序块的顺序很重要,但是与构造函数混合的初始化程序块的顺序并不重要
  • 抽象类也可以同时具有静态和实例初始化程序块。

代码演示-

abstract class Aircraft {

    protected Integer seatCapacity;

    {   // Initial block 1, Before Constructor
        System.out.println("Executing: Initial Block 1");
    }

    Aircraft() {
        System.out.println("Executing: Aircraft constructor");
    }

    {   // Initial block 2, After Constructor
        System.out.println("Executing: Initial Block 2");
    }

}

class SupersonicAircraft extends Aircraft {

    {   // Initial block 3, Internalizing a instance variable
        seatCapacity = 300;
        System.out.println("Executing: Initial Block 3");
    }

    {   // Initial block 4
        System.out.println("Executing: Initial Block 4");
    }

    SupersonicAircraft() {
        System.out.println("Executing: SupersonicAircraft constructor");
    }
}

创建SupersonicAircraft的实例将按以下顺序生成日志

Executing: Initial Block 1
Executing: Initial Block 2
Executing: Aircraft constructor
Executing: Initial Block 3
Executing: Initial Block 4
Executing: SupersonicAircraft constructor
Seat Capacity - 300

答案 10 :(得分:0)

除了前面的回答中所说的以外,积木可以是library(tidyverse) ggplot() + geom_density(data=df1, aes(x=x, color='darkblue'), fill='lightblue', alpha=0.5) + geom_density(data=df2, aes(x=y, color='darkred'), fill='indianred1', alpha=0.5) + scale_color_manual('Legend Title', limits=c('x', 'y'), values = c('darkblue','darkred')) + guides(colour = guide_legend(override.aes = list(pch = c(21, 21), fill = c('darkblue','darkred')))) + theme(legend.position = 'bottom')+ scale_color_manual("Legend title", values = c("blue", "red")) ..从来没有觉得我需要使用它,但是,它就在那里