Необходимость статического блока в Java
Я обнаружил, что в Java есть функция, которая называется static block
, который включает код, который выполняется при первой загрузке класса (я не понимаю, что означает "загружен", означает ли он инициализирован?). Есть ли причина делать бит инициализации внутри статического блока, а не в конструкторе? Я имею в виду, что даже конструктор делает то же самое, делает все необходимое, когда класс сначала инициализируется. есть ли что-нибудь, что статический блок выполняет, который конструктор не можешь?
11 ответов
если класс имеет статические члены, требующие сложной инициализации, a 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
, etc.) создаст исключение.
справедливости ради, это не полный ответ на ваш вопрос. The 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
блок было бы неудобно заменить будет "мастер" класс, который должен инициализировать несколько других классов ровно один раз.
public class Master {
static {
SlaveClass1.init();
SlaveClass2.init(SlaveClass1.someInitializedValue);
// etc.
}
}
особенно, если вы не хотите жестко привязать какую-либо зависимость к SlaveClass2
on 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
}
};
конструктор вызывается при создании экземпляра класса.
статический блок вызывается, когда загрузчик классов загружает это определение класса, чтобы мы могли инициализировать статические члены этого класса. Мы не должны инициализировать статические члены из конструктора, поскольку они являются частью определения класса not object
статический инициализатор будет запущен, если мы инициализируем класс, это не требует создания экземпляра класса. Но конструктор запускается только тогда, когда мы делаем экземпляр класса.
например:
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
мы никогда не создавали экземпляр, поэтому конструктор не вызывается, но вызывается статический инициализатор.
если мы делаем экземпляр класса, статические initilizer и запуск конструктора. Никакие сюрпризы.
MyClass x = new MyClass();
выход:
I am static initializer
I am constructor
обратите внимание, что если мы бежим:
MyClass x;
выход: (пусто)
объявив переменную x
не требуется MyClass
для инициализации, поэтому статический инициализатор не запускается.
статический инициализатор запускается при загрузке класса, даже если вы никогда не создаете объекты этого типа.
- не все классы предназначены для создания экземпляров. Конструктор может никогда не вызываться. Возможно, это даже личное.
- вы можете получить доступ к статическим полям класса перед выполнением конструктора.
- статический инициализатор запускается только один раз при загрузке класса. Конструктор вызывается для каждого объекта этого типа создать экземпляр.
вы не можете инициализировать статические переменные с конструктором ... или, по крайней мере, вы, вероятно,Не стоит, и это не будет особенно полезно.
особенно, когда вы пытаетесь инициализировать статические константы, которые требуют значительной логики для генерации, это действительно должно произойти в статическом блоке, а не в конструкторе.
Это две разные вещи. Конструктор используется для инициализации одного экземпляра класса, статический блок инициализации инициализирует статические члены во время загрузки класса.
статический блок делает разные вещи, чем конструктор . В основном существуют две разные концепции.
статический блок инициализируется при загрузке класса в память, это означает, что JVM читает байтовый код u'R. Инициализация не может быть ничем, это может быть инициализация переменной или любая другая вещь, которая должна быть разделена всеми объектами этого класса
а конструктор инициализирует переменную только для этого объекта .
статический блок reqly полезен, когда вам нужно выполнить какое-то действие, даже если экземпляры еще не созданы. Например, для инициализации статической переменной с нестатическим значением.
статический блок полезен над конструкторами, когда вам нужно выполнить какое-то действие, даже если экземпляры еще не созданы. Например, для инициализации статической переменной с нестатическим значением.
один из способов понять статический блок; Он действует как конструктор. однако, разница между двумя статический блок создает экземпляр класса или статических переменных, а конструктор используется для создания экземпляра переменных объекта
рассмотрим следующий класс
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");