Статический инициализатор в Java

мой вопрос касается одного конкретного использования статического ключевого слова. Можно использовать static ключевое слово для покрытия блока кода в классе, который не принадлежит какой-либо функции. Например, следующий код компилируется:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

если убрать static ключевое слово жалуется, потому что переменная a is final. Однако можно удалить оба final и static ключевые слова и сделать его компиляции.

это сбивает меня с толку в обоих направлениях. Как я предполагается, что раздел кода не принадлежит какому-либо методу? Как можно вызвать его? В общем, какова цель этого использования? Или лучше, где я могу найти документацию об этом?

9 ответов


блок кода со статическим модификатором означает класс инициализатор; без модификатора static блоке кода экземпляр инициализатор.

инициализаторы класса выполняются в том порядке, в котором они определены (сверху вниз, как и простые инициализаторы переменных), когда класс загружен (на самом деле, когда он разрешен, но это формальность).

инициализаторы экземпляра выполняются в порядке, определенном, когда класс экземпляр создается непосредственно перед выполнением кода конструктора, сразу после вызова супер конструктора.

если убрать static с int a, оно становится переменной экземпляра, который вы не можете получить доступ из статического блока инициализации. Это не удастся скомпилировать с ошибкой "на нестатическую переменную a нельзя ссылаться из статического контекста".

если вы также удалить static из блока инициализатора он становится экземпляром инициализатор и так int a инициализируется при строительстве.


уфф! что такое статический инициализатор?

статический инициализатор-это static {} блок кода внутри класса java и выполняется только один раз перед вызовом конструктора или метода main.

ОК! Сказать мне больше...

  • - это блок кода static { ... } внутри любого класса java. и выполняется виртуальной машиной при вызове класса.
  • нет return поддерживаются операторы.
  • нет аргументов поддерживаемый.
  • нет this или super поддерживаются.

хм, где я могу его использовать?

можно использовать везде, где вы чувствуете себя хорошо :) это просто. Но я вижу, что большую часть времени он используется при подключении к базе данных, API init, регистрации и т. д.

Не просто лай! где пример?

package com.example.learnjava;

import java.util.ArrayList;

public class Fruit {

    static {
        System.out.println("Inside Static Initializer.");

        // fruits array
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Pear");

        // print fruits
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        System.out.println("End Static Initializer.\n");
    }

    public static void main(String[] args) {
        System.out.println("Inside Main Method.");
    }
}

выход???

Внутри Статического Инициализатора.

Яблоко

оранжевый

груша

Завершить Статический Инициализатор.

Внутри Метода Main.

надеюсь, что это помогает!


на static блок является "статическим инициализатором".

он автоматически вызывается при загрузке класса, и нет другого способа вызвать его (даже через отражение).

Я лично только когда-либо использовал его при написании кода JNI:

class JNIGlue {
    static {
        System.loadLibrary("foo");
    }
}

это непосредственно из http://www.programcreek.com/2011/10/java-class-instance-initializers/

1. Приказ Об Исполнении

посмотрите на следующий класс, вы знаете, какой из них выполняется первым?

public class Foo {

    //instance variable initializer
    String s = "abc";

    //constructor
    public Foo() {
        System.out.println("constructor called");
    }

    //static initializer
    static {
        System.out.println("static initializer called");
    }

    //instance initializer
    {
        System.out.println("instance initializer called");
    }

    public static void main(String[] args) {
        new Foo();
        new Foo();
    }
}

выход:

статический инициализатор называется

инициализатор экземпляра под названием

конструктор под названием

инициализатор экземпляра под названием

конструктор под названием

2. Как сделать экземпляр Java инициализатор работает?

инициализатор экземпляра выше содержит оператор println. Чтобы понять, как это работает, мы можем рассматривать его как оператор присваивания переменных, например,b = 0. Это может сделать понимание более очевидным.

вместо

int b = 0, вы могли бы написать

int b;
b = 0;

таким образом, инициализаторы экземпляра и инициализаторы переменных экземпляра в значительной степени тот же.

3. Когда полезны инициализаторы экземпляра?

инициализаторы экземпляра используются редко, но все же это может быть полезной альтернативой инициализаторам переменных экземпляра, если:

  1. код инициализатора должен обрабатывать исключения
  2. выполнить вычисления, которые не могут быть выражены с помощью инициализатора переменной экземпляра.

конечно, такой код может быть написан в конструкторах. Но если класс имел несколько конструкторы, вам придется повторить код в каждом конструкторе.

С инициализатором экземпляра вы можете просто написать код один раз, и он будет выполнен независимо от того, какой конструктор используется для создания объекта. (Я думаю, это просто концепция, и она используется не часто.)

другим случаем, в котором инициализаторы экземпляра полезны, являются анонимные внутренние классы, которые вообще не могут объявлять никаких конструкторов. (Будет ли это хорошее место для размещения журнала функции?)

благодаря Derhein.

также обратите внимание, что анонимные классы, реализующие интерфейсы [1], не имеют конструкторов. Поэтому инициализаторы экземпляров необходимы для выполнения любых видов выражений во время построения.


"final" гарантирует, что переменная должна быть инициализирована до конца кода инициализатора объекта. Аналогично, "static final" гарантирует, что переменная будет инициализирована к концу кода инициализации класса. Исключение" статического " из кода инициализации превращает его в код инициализации объекта; таким образом, ваша переменная больше не удовлетворяет его гарантиям.


вы не будете писать код в статический блок, который должен быть вызван в любом месте программы. Если цель кода должна быть вызвана, вы должны поместить его в метод.

вы можете писать статические блоки инициализаторов для инициализации статических переменных при загрузке класса, но этот код может быть более сложным..

статический блок инициализации выглядит способ без имени, без аргументов и без возвращаемого типа. Поскольку вы никогда не называете его, ему не нужно имя. Вызывается только тогда, когда виртуальная машина загружает класс.


когда разработчик использует блок инициализатора, компилятор Java копирует инициализатор в каждый конструктор текущего класса.

пример:

следующий код:

class MyClass {

    private int myField = 3;
    {
        myField = myField + 2;
        //myField is worth 5 for all instance
    }

    public MyClass() {
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

эквивалентно:

class MyClass {

    private int myField = 3;

    public MyClass() {
        myField = myField + 2;
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        myField = myField + 2;
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

Я надеюсь, что мой пример будет понят разработчиками.


статический блок кода можно использовать для создания экземпляра или инициализации переменных класса (в отличие от переменных объекта). Таким образом, объявление "a" static означает, что только один общий для всех тестовых объектов, а статический блок кода инициализирует "a" только один раз, когда тестовый класс загружается первым, независимо от того, сколько тестовых объектов создано.


ключевое слово Static можно использовать с классом, переменной, методом и блоком. Статические члены принадлежат классу, а не конкретному экземпляру, это означает, что если вы делаете член статическим, вы можете получить к нему доступ без объекта. Пример :

здесь у нас есть статический метод myStatic (), мы можем вызвать этот метод без какого-либо объекта, потому что когда мы делаем член статическим, он становится уровнем класса. Если мы удалим ключевое слово static и сделаем его нестатическим, нам нужно создать объект класса в приказываю назвать его

статические члены являются общими для всех экземпляров(объектов) класса, а нестатические члены отдельно для каждого экземпляра класса.

class SimpleStaticExample {
//static method
static void myStatic()
{
    System.out.println("my Static Method");
}

public static void main(String[] args)
{
      /* You can see that we are calling this
       * method without creating any object. 
       */
       myStatic();
 }
}

вывод : мой статический метод