Подтвердить что ты не робот

Необходимость статического блока в Java

Я обнаружил, что в Java есть функция с именем static block, которая включает код, который выполняется при первом загрузке класса (я не понимаю, что означает "загруженный", означает ли это инициализация?). Есть ли причина сделать бит инициализации внутри статического блока, а не в конструкторе? Я имею в виду, что даже конструктор делает то же самое, делает все необходимое, когда класс сначала инициализируется. есть ли что-либо, что статический блок выполняет, который конструктор не может сделать?

4b9b3361

Ответ 1

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

public static final Map<String, String> initials = new HashMap<String, String>();

Однако, если вы хотите заполнить его один раз, вы не можете сделать это с помощью встроенного объявления. Для этого вам нужен блок static:

public static final Map<String, String> initials = new HashMap<String, String>();
static {
    initials.put("AEN", "Alfred E. Newman");
    // etc.
}

Если вы хотите быть еще более защищенным, вы можете сделать это:

public static final Map<String, String> initials;
static {
    HashMap<String, String> map = new HashMap<String, String>()
    map.put("AEN", "Alfred E. Newman");
    // etc.
    initials = Collections.unmodifiableMap(map);
}

Обратите внимание, что вы не можете инициализировать initials в строке как неизменяемую карту, потому что тогда вы не могли ее заполнить! Вы также не можете сделать это в конструкторе, потому что простой вызов одного из модифицирующих методов (put и т.д.) Сгенерирует исключение.

Если честно, это не полный ответ на ваш вопрос. Блок static все еще можно устранить с помощью закрытой статической функции:

public static final Map<String, String> initials = makeInitials();

private static Map<String, String> makeInitials() {
    HashMap<String, String> map = new HashMap<String, String>()
    map.put("AEN", "Alfred E. Newman");
    // etc.
    return Collections.unmodifiableMap(map);
}

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

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

public class Master {
    static {
        SlaveClass1.init();
        SlaveClass2.init(SlaveClass1.someInitializedValue);
        // etc.
    }
}

В частности, если вы не хотите жестко привязывать какую-либо зависимость к SlaveClass2 на SlaveClass1, необходим некоторый мастер-код, подобный этому. Подобные вещи, безусловно, не принадлежат конструктору.

Обратите внимание, что есть также нечто, называемое блоком инициализатора экземпляра. Это анонимный блок кода, который запускается при создании каждого экземпляра. (Синтаксис подобен блоку static, но без ключевого слова static.) Это особенно полезно для анонимных классов, поскольку они не могут иметь именованных конструкторов. Вот пример из реальной жизни. Поскольку (непостижимо) GZIPOutputStream не имеет конструктора или какого-либо вызова API, с помощью которого вы можете указать уровень сжатия, а уровень сжатия по умолчанию равен none, вам необходимо создать подкласс GZIPOutputStream для получения любого сжатия. Вы всегда можете написать явный подкласс, но может быть удобнее написать анонимный класс:

OutputStream os = . . .;
OutputStream gzos = new GZIPOutputStream(os) {
    {
        // def is an inherited, protected field that does the actual compression
        def = new Deflator(9, true); // maximum compression, no ZLIB header
    }
};

Ответ 2

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

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

Ответ 3

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

Например:

class MyClass
{   
    static
    {
        System.out.println("I am static initializer");
    }
    MyClass()
    {
        System.out.println("I am constructor");
    }

    static void staticMethod()
    {
        System.out.println("I am static method");
    }
}

Если мы запустим:

MyClass.staticMethod();

Вывод:

I am static initializer
I am static method

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

Если мы создадим экземпляр класса, запускается как статический инициализатор, так и конструктор. Никаких сюрпризов.

MyClass x = new MyClass();

Вывод:

I am static initializer
I am constructor

Обратите внимание, что если мы запустим:

MyClass x;

Выход: (пустой)

Объявление переменной x не требует инициализации MyClass, поэтому статический инициализатор не запускается.

Ответ 4

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

  • Не все классы предназначены для создания экземпляров. Конструктор никогда не будет вызван. Это может быть даже конфиденциально.
  • Вы можете захотеть получить доступ к статическим полям класса перед запуском конструктора.
  • Статический инициализатор запускается только один раз, когда класс загружается. Конструктор вызывается для каждого объекта того типа, который вы создаете.

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

Статический блок

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

тогда как конструктор инициализирует переменную только для этого объекта.

Ответ 9

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

Ответ 10

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

Ответ 11

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

Рассмотрим следующий класс

public class Part{

  String name;
  static String producer;

  public Part(String name){
      this.name = name;
  }

  static {
    producer = "Boeing";
  }

}
Для объектов

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

Part engine = new Part("JetEngine");
Part Wheel = new Part("JetWheel");