Статический инициализатор в 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 равна final. Однако можно удалить как ключевые слова final, так и static и скомпилировать его.

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

Ответ 1

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

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

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

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

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

Ответ 2

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

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

OK! Скажите мне больше...

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

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

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

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

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

Выход???

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

Яблоко

Orange

груша

Конечный статический инициализатор.

Внутри основного метода.

Надеюсь, это поможет!

Ответ 3

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

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

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

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

Ответ 4

Это прямо из 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], не имеют конструкторов. Поэтому инициализаторы экземпляра нуждаются в выполнении любых выражений во время построения.

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

Ответ 8

когда разработчик использует блок инициализатора, компилятор 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
    }
}

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

Ответ 9

Определение статического блока из: Статическое ключевое слово в java

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

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

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

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

public enum ErrorCodes {
    BUSINESS_ERROR(100), SERVER_ERROR(500), NETWORK_ERROR(1000);

    private int errorCode;
    // This field maps each error code numeric value to a corresponding Enum instance.
    private static Map<Integer, ErrorCodes> errorCodeByErrorNumber = new HashMap<Integer, ErrorCodes>();

    static {
        for (ErrorCodes errorCode : ErrorCodes.values()) {
            errorCodeByErrorNumber.put(errorCode.getErrorCode(), errorCode);
        }
    }

    private ErrorCodes(int errorCode) {
        this.errorCode = errorCode;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public static ErrorCodes getErrorCodeByNumber(Integer dayNumber) {
        return errorCodeByErrorNumber.get(dayNumber);
    }
}