Когда вы объявляете класс как
public class Server {
private int pingFrequency = 500;
public Server() {
}
}
ничем не отличается от
public class Server {
private int pingFrequency;
public Server() {
pingFrequency = 500;
}
}
или
public class Server {
private int pingFrequency;
{
pingFrequency = 500;
}
public Server() {
}
}
Фактически, все три варианта компилируются в один и тот же байт-код. Код всех инициализаторов полей и блоков инициализатора экземпляра копируется в каждый конструктор этого класса, прямо между вызовом супер-конструктора и остальной частью конструктора. [ ПСБ §12.5 ]
¹, который не делегирует другому конструктору этого класса
Единственный способ изменить присвоенное значение - изменить код всех конструкторов, чтобы изменить присвоение. Это не может быть сделано с помощью Reflection, но только с помощью инструментов манипулирования байт-кодом.
Обратите внимание, что когда поле было объявлено final
, как
public class Server {
private final int pingFrequency = 500;
public Server() {
}
}
в байт-коде будет атрибут, сообщающий постоянное значение [ JVMS §4.7.2 ], дополнительно к назначению. Однако для такой постоянной времени компиляции каждый обычный доступ на чтение будет заменен постоянным значением во время компиляции [ JLS §13.1 ], поэтому даже изменение назначения не будет иметь никакого эффекта в этом случае (и при этом не будет изменение атрибута) [ JLS §13.4.9 ]. Попытка заменить фактическое использование поля создаст проблему, заключающуюся в том, что вы не сможете отличить их от других вариантов использования постоянного числа 500
.
Если бы поле было static
и final
, присваивания не было вообще, атрибут константного значения использовался бы для инициализации поля, однако изменение его имело бы такой же небольшой эффект, как и для поля экземпляра константы, поскольку доступ к полю все еще был заменен старым постоянным значением.