Если класс Java имеет поле, которое инициализируется лениво или по требованию, как мы можем гарантировать, что доступ к ленивому полю осуществляется через его метод инициализации доступа?В Java, как мы защищаем доступ к ленивым полям?
В контексте контекста у нас недавно возникла ситуация, когда разработчик добавил доступ к объекту, который был инициализирован лениво, но не через его метод доступа к инициализации. Это не было обнаружено при компиляции или в модульных тестах, но затем вызвало ошибки времени выполнения.
Например, в следующем SSCCE, _lazyObject
инициализируется методом getLazyObject()
. Однако, если есть другие методы (в классе, поскольку у него уже есть модификатор доступа private
), который хотел бы использовать _lazyObject
, нам нужно получить доступ с помощью метода getLazyObject()
, так как иначе он, возможно, не был инициализирован.
public class MyObject {
private transient volatile Object _lazyObject;
public Object getLazyObject() {
if (_lazyObject == null) {
synchronized (this) {
if (_lazyObject == null) {
_lazyObject = new Object();
}
}
}
return _lazyObject;
}
public void doSomething() {
Object a = _lazyObject; // may be null - will compile, but may cause runtime errors!
Object b = getLazyObject(); // subject to exceptions, will not be null - this is how it should be accessed.
// do something...
}
}
Как мы можем гарантировать, что доступ _lazyObject
осуществляется через getLazyObject()
?
- Возможно ли это в кодексе в пределах
MyObject
? - В качестве альтернативы можно ли это обеспечить посредством модульных испытаний?
Вы могли бы включать в себя утверждение, чтобы проверить '_lazyObject' был экземпляр' утверждать _lazyObject = нуль! "! Используйте getLazyObject()" 'для целей модульного тестирования , Я предполагаю, что у MyObject есть частный конструктор, чтобы другие классы не запускали экземпляр MyObject, хотя это не то, о чем ваша проблема. –
Является ли ленивый объект действительно типом объекта или он более конкретный? – Gimby
@Gimby - это всегда более конкретный. Мы используем ленивую инициализацию довольно широко - особенно при сериализации классов/совместном использовании в JVM, поэтому обычно это нечто слишком большое, чтобы сериализовать (т. Е. Быстрее инициализировать) или что-то, что не может быть сериализовано. – amaidment