什么是初始化块?

dgiusagp  于 2021-07-03  发布在  Java
关注(0)|答案(10)|浏览(501)

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

webghufk

webghufk1#

初始化块在初始化类时和调用构造函数之前执行。它们通常放置在支架中的构造函数上方。在你的课堂上完全没有必要包括他们。
它们通常用于初始化引用变量。这一页解释得很好

nszi6y05

nszi6y052#

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
zf9nrax1

zf9nrax13#

除了前面的回答中所说的以外,还可以使用积木 synchronized .. 从来没有觉得我需要用它,但是,它就在那里

5cnsuln7

5cnsuln74#

想补充@aioobe的答案吗
执行顺序:
超类的静态初始化块
类的静态初始化块
超类示例初始化块
超类的构造函数
类的示例初始化块
类的构造函数。
另外要记住几点(第一点是重复@aioobe的答案):
静态初始化块中的代码将在类加载时执行(是的,这意味着每个类加载只执行一次),在类的任何示例被构造之前和任何静态方法被调用之前。
示例初始化块实际上是由java编译器复制到类的每个构造函数中的。所以每次示例初始化块中的代码在构造函数中的代码之前执行。

hsgswve4

hsgswve45#

这个问题还不完全清楚,但这里简要介绍了初始化对象中数据的方法。假设您有一个类a,它包含一个对象列表。
1) 在字段声明中输入初始值:

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

2) 在构造函数中指定初始值:

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

它们都假设您不想将“data”作为构造函数参数传递。
如果将重载构造函数与上述内部数据混合使用,事情会变得有点棘手。考虑:

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

两者(或多或少)是等价的。
我希望这能给您一些关于如何初始化对象中的数据的提示。我不会谈论静态初始化块,因为这可能是目前有点先进。
编辑:我将您的问题解释为“如何初始化示例变量”,而不是“初始化程序块如何工作”,因为初始化程序块是一个相对高级的概念,从问题的语气来看,您似乎在问更简单的概念。我可能错了。

3yhwsihp

3yhwsihp6#

再加上@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
5cnsuln7

5cnsuln77#

首先,有两种类型的初始化块:
示例初始化块,以及
静态初始化块。
此代码应说明它们的用法以及它们的执行顺序:

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.

如果您希望运行某些代码,而不管使用哪个构造函数,或者希望对匿名类执行某些示例初始化,则示例初始化块非常有用。

xkftehaa

xkftehaa8#

示例代码,在这里被批准作为一个答案是正确的,但我不同意它。它没有显示正在发生的事情,我将向您展示一个很好的示例来了解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中,不需要任何示例。因此,从外部类(未定义静态成员的类)正确访问静态成员的方法是,先使用点后面的类名,然后使用要访问的静态成员(模板: <CLASS_NAME>.<STATIC_VARIABLE_NAME> ).
现在让我们看看上面的代码:
入口点是主方法-只有三行代码。我想参考目前被批准的例子。根据它,在打印“静态初始化块”之后必须打印的第一件事是“初始化块”,我不同意,非静态初始化块不是在构造函数之前调用的,它是在定义初始化块的类的构造函数的任何初始化之前调用的。当您创建一个对象(类的示例)时,首先涉及类的构造函数,然后当您输入构造函数时,调用的第一部分是隐式(默认)超级构造函数或显式超级构造函数,或者显式调用另一个重载构造函数(但在某个点上,如果存在一个重载的链)构造函数,最后一个构造函数隐式或显式地调用超级构造函数)。
有一个对象的多态创建,但是在进入类b及其主方法之前,jvm初始化所有类(静态)变量,然后通过静态初始化块(如果有的话),然后进入类b并开始执行主方法。它转到类b的构造函数,然后立即(隐式)调用类a的构造函数,使用多态性在类a的构造函数体中调用的方法(重写方法)是在类b中定义的方法,在这种情况下,在重新初始化之前使用名为instancevariable的变量。关闭类b的构造函数后,线程返回到类b的构造函数,但它首先进入非静态初始化块,然后再打印“constructor”。为了更好地理解如何用ide调试它,我更喜欢eclipse。

5ktev3wc

5ktev3wc9#

很好的答案,艾奥比多加了几分

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

这就像陈述显而易见的东西,但似乎更清楚一点。

fykwrbwg

fykwrbwg10#

initializer块包含在创建示例时始终执行的代码。它用于声明/初始化类的各种构造函数的公共部分。
初始化构造函数和初始化程序块的顺序无关紧要,初始化程序块总是在构造函数之前执行。
如果我们想对一个类的所有对象执行一次代码呢?
我们在java中使用静态块。

相关问题