简体   繁体   English

什么是初始化块?

[英]What is an initialization block?

We can put code in a constructor or a method or an initialization block.我们可以将代码放在构造函数或方法或初始化块中。 What is the use of initialization block?初始化块有什么用? Is it necessary that every java program must have it?是不是每个java程序都必须有?

First of all, there are two types of initialization blocks :首先,有两种类型的初始化块

  • instance initialization blocks , and实例初始化块,和
  • static initialization blocks .静态初始化块

This code should illustrate the use of them and in which order they are executed:这段代码应该说明它们的使用以及它们的执行顺序:

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();
    }
}

Prints:印刷:

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

Instance itialization blocks are useful if you want to have some code run regardless of which constructor is used or if you want to do some instance initialization for anonymous classes.如果您想运行一些代码而不管使用哪个构造函数,或者如果您想为匿名类进行一些实例初始化,则实例初始化块很有用。

would like to add to @aioobe's answer想添加到@aioobe 的答案中

Order of execution:执行顺序:

  1. static initialization blocks of super classes超类的静态初始化块

  2. static initialization blocks of the class类的静态初始化块

  3. instance initialization blocks of super classes超类的实例初始化块

  4. constructors of super classes超类的构造函数

  5. instance initialization blocks of the class类的实例初始化块

  6. constructor of the class.类的构造函数。

A couple of additional points to keep in mind (point 1 is reiteration of @aioobe's answer):需要记住的另外几点(第 1 点是重复@aioobe 的回答):

  1. The code in static initialization block will be executed at class load time (and yes, that means only once per class load), before any instances of the class are constructed and before any static methods are called.静态初始化块中的代码将在类加载时执行(是的,这意味着每个类加载一次),在构造类的任何实例之前和调用任何静态方法之前。

  2. The instance initialization block is actually copied by the Java compiler into every constructor the class has.实例初始化块实际上由 Java 编译器复制到类的每个构造函数中。 So every time the code in instance initialization block is executed exactly before the code in constructor.所以每次实例初始化块中的代码都恰好在构造函数中的代码之前执行。

nice answer by aioobe adding few more points 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");
    }
}

this gives这给

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

its like stating the obvious but seems a little more clear.它就像陈述显而易见的,但似乎更清楚一点。

The sample code, which is approved as an answer here is correct, but I disagree with it.此处被批准为答案的示例代码是正确的,但我不同意。 It does not shows what is happening and I'm going to show you a good example to understand how actually the JVM works:它没有显示正在发生的事情,我将向您展示一个很好的例子来了解 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");
        }
    }

Before to start commenting on the source code, I'll give you a short explanation of static variables of a class:在开始评论源代码之前,我会给你一个类的静态变量的简短解释:

First thing is that they are called class variables, they belong to the class not to particular instance of the class.首先,它们被称为类变量,它们属于类而不属于类的特定实例。 All instances of the class share this static(class) variable.类的所有实例共享这个静态(类)变量。 Each and every variable has a default value, depending on primitive or reference type.每个变量都有一个默认值,具体取决于原始类型或引用类型。 Another thing is when you reassign the static variable in some of the members of the class (initialization blocks, constructors, methods, properties) and doing so you are changing the value of the static variable not for particular instance, you are changing it for all instances.另一件事是,当您在类的某些成员(初始化块、构造函数、方法、属性)中重新分配静态变量并这样做时,您正在更改静态变量的值,而不是针对特定实例,您正在更改所有实例。 To conclude static part I will say that the static variables of a class are created not when you instantiate for first time the class, they are created when you define your class, they exist in JVM without the need of any instances.总结静态部分,我会说类的静态变量不是在您第一次实例化类时创建的,而是在您定义类时创建的,它们存在于 JVM 中而不需要任何实例。 Therefor the correct access of static members from external class (class in which they are not defined) is by using the class name following by dot and then the static member, which you want to access (template: <CLASS_NAME>.<STATIC_VARIABLE_NAME> ).因此,从外部类(未定义它们的类)中正确访问静态成员是使用类名<CLASS_NAME>.<STATIC_VARIABLE_NAME>点,然后是您要访问的静态成员(模板: <CLASS_NAME>.<STATIC_VARIABLE_NAME> ) .

Now let's look at the code above:现在让我们看看上面的代码:

The entry point is the main method - there are just three lines of code.入口点是主要方法——只有三行代码。 I want to refer to the example which is currently approved.我想参考目前批准的例子。 According to it the first thing which must be printed after printing "Static Initialization block" is "Initialization block" and here is my disagreement, the non-static initialization block is not called before the constructor, it is called before any initializations of the constructors of the class in which the initialization block is defined.根据它,打印“静态初始化块”后必须打印的第一件事是“初始化块”,这是我的不同意见,非静态初始化块不是在构造函数之前调用,而是在构造函数的任何初始化之前调用定义初始化块的类。 The constructor of the class is the first thing involved when you create an object (instance of the class) and then when you enter the constructor the first part called is either implicit (default) super constructor or explicit super constructor or explicit call to another overloaded constructor (but at some point if there is a chain of overloaded constructors, the last one calls a super constructor, implicitly or explicitly).类的构造函数是创建对象(类的实例)时涉及的第一件事,然后当您进入构造函数时,调用的第一部分是隐式(默认)超级构造函数或显式超级构造函数或对另一个重载的显式调用构造函数(但在某些时候,如果存在一串重载构造函数,最后一个会隐式或显式调用超级构造函数)。

There is polymorphic creation of an object, but before to enter the class B and its main method, the JVM initializes all class(static) variables, then goes through the static initialization blocks if any exist and then enters the class B and starts with the execution of the main method.对象的创建是多态的,但是在进入B类及其main方法之前,JVM初始化所有类(静态)变量,然后如果存在静态初始化块,然后进入B类并开始执行main方法。 It goes to the constructor of class B then immediately (implicitly) calls constructor of class A, using polymorphism the method(overridden method) called in the body of the constructor of class A is the one which is defined in class B and in this case the variable named instanceVariable is used before reinitialization.它转到类 B 的构造函数,然后立即(隐式)调用类 A 的构造函数,使用多态性,在类 A 的构造函数体中调用的方法(重写方法)是在类 B 中定义的方法,在这种情况下在重新初始化之前使用名为 instanceVariable 的变量。 After closing the constructor of class B the thread is returned to constructor of class B but it goes first to the non-static initialization block before printing "Constructor".关闭类 B 的构造函数后,线程返回到类 B 的构造函数,但它在打印“构造函数”之前首先进入非静态初始化块。 For better understanding debug it with some IDE, I prefer Eclipse.为了更好地理解用一些 IDE 调试它,我更喜欢 Eclipse。

Initializer block contains the code that is always executed whenever an instance is created.初始化程序块包含在创建实例时始终执行的代码。 It is used to declare/initialise the common part of various constructors of a class.它用于声明/初始化类的各种构造函数的公共部分。

The order of initialization constructors and initializer block doesn't matter, initializer block is always executed before constructor.初始化构造函数和初始化块的顺序无关紧要,初始化块总是在构造函数之前执行。

What if we want to execute some code once for all objects of a class?如果我们想对一个类的所有对象执行一次代码怎么办?

We use Static Block in Java.我们在 Java 中使用静态块。

除了之前的答案中所说的,块可以synchronized ..从来没有觉得我需要使用它,但是,它就在那里

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();
    }

}

Output:输出:

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

Initialization blocks are executed whenever the class is initialized and before constructors are invoked.初始化块在类被初始化时和构造函数被调用之前执行。 They are typically placed above the constructors within braces.它们通常放置在大括号内的构造函数之上。 It is not at all necessary to include them in your classes.完全没有必要将它们包含在您的类中。

They are typically used to initialize reference variables.它们通常用于初始化引用变量。 This page gives a good explanation这个页面给出了很好的解释

The question is not entirely clear, but here's a brief description of ways you can initialise data in an object.这个问题并不完全清楚,但这里简要描述了您可以在对象中初始化数据的方法。 Let's suppose you have a class A that holds a list of objects.假设您有一个包含对象列表的类 A。

1) Put initial values in the field declaration: 1)将初始值放在字段声明中:

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

2) Assign initial values in the constructor: 2)在构造函数中分配初始值:

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

These both assume that you do not want to pass "data" as a constructor argument.这些都假设您不想将“数据”作为构造函数参数传递。

Things get a little tricky if you mix overloaded constructors with internal data like above.如果将重载的构造函数与上述内部数据混合使用,事情就会变得有点棘手。 Consider:考虑:

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;
    }
}

Notice that there is a lot of repeated code.请注意,有很多重复的代码。 You can fix this by making constructors call each other, or you can have a private initialisation method that each constructor calls:您可以通过使构造函数相互调用来解决此问题,或者您可以拥有每个构造函数调用的私有初始化方法:

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;
    }
}

or或者

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;
    }
}

The two are (more or less) equivalent.两者是(或多或少)等价的。

I hope that gives you some hints on how to initialise data in your objects.我希望这能给你一些关于如何在你的对象中初始化数据的提示。 I won't talk about static initialisation blocks as that's probably a bit advanced at the moment.我不会谈论静态初始化块,因为目前这可能有点先进。

EDIT: I've interpreted your question as "how do I initialise my instance variables", not "how do initialiser blocks work" as initialiser blocks are a relatively advanced concept, and from the tone of the question it seems you're asking about the simpler concept.编辑:我已经将您的问题解释为“我如何初始化我的实例变量”,而不是“初始化块如何工作”,因为初始化块是一个相对高级的概念,从问题的语气来看,您似乎在问更简单的概念。 I could be wrong.我可能是错的。

Just to add to the excellent answers from @aioobe and @Biman Tripathy .只是为了补充@aioobe@Biman Tripathy的优秀答案。

A static initializer is the equivalent of a constructor in the static context.静态初始化器相当于静态上下文中的构造函数。 which is needed to setup the static environment.这是设置静态环境所必需的。 A instance initializer is best for anonymous inner classes.实例初始值设定项最适合匿名内部类。

  • It is also possible to have multiple initializer blocks in class类中也可以有多个初始化块
  • When we have multiple initializer blocks they are executed (actually copied to constructors by JVM) in the order they appear当我们有多个初始化块时,它们会按照它们出现的顺序执行(实际上是由 JVM 复制到构造函数中)
  • Order of initializer blocks matters, but order of initializer blocks mixed with Constructors doesn't初始化块的顺序很重要,但与构造函数混合的初始化块的顺序并不重要
  • Abstract classes can also have both static and instance initializer blocks.抽象类也可以同时具有静态和实例初始化块。

Code Demo -代码演示 -

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");
    }
}

An instance creation of SupersonicAircraft will produce logs in below order 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM