子类中的 Kotlin 惰性初始化
Kotlin lazy initialization in subclass
我正在尝试构建一个具有在子类中初始化的属性的字符串。
我阅读了有关延迟初始化的内容,但不知何故这并没有像我预期的那样工作。
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
private val packageName by lazy { packageName() }
private val processName by lazy { processName() }
val processFullName: String = "$moduleName/$packageName.$processName"
protected abstract fun packageName(): String
protected abstract fun processName(): String
}
class WorkerFullNameBuilder(
private val jmsDirection: JmsDirectionEnumeration,
technicalDomain: TechnicalDomainEnumeration,
private val cdmCode: String) : SubProcessFullNameBuilder(technicalDomain) {
override fun packageName() = "$moduleName.workers.${jmsDirection.value().toLowerCase()}.${cdmCode.toLowerCase()}"
override fun processName() = "Worker"
}
因为我已经覆盖了 packageName()
和 processName()
属性,我希望在调用 packageName
属性 时它会使用子类的实现。
但是当我调用 processFullName
属性 时,它会抛出 java.lang.NullPointerException
.
val builder = WorkerFullNameBuilder(JmsDirectionEnumeration.ESB_IN, TechnicalDomainEnumeration.INFOR, "ccmd")
val name = builder.processFullName
如何以正确的方式初始化 packageName 和 processName 属性?
这是 calling a non-final method in a constructor 的情况,因此访问未初始化的变量。
这一行还在热切的求值,建基class的时候:
val processFullName: String = "$moduleName/$packageName.$processName"
要获取两个惰性属性的值,这将调用抽象方法,其中 packageName()
指的是 jmsDirection
和 cdmCode
指的是 return它的值 - 这些属性尚未初始化,因为它们的值是在 超级class 构造函数 运行 之后设置的。这是 subclass' 构造函数的简化版本,反编译回 Java:
public WorkerFullNameBuilder(@NotNull JmsDirectionEnumeration jmsDirection, @NotNull TechnicalDomainEnumeration technicalDomain, @NotNull String cdmCode) {
super(technicalDomain);
this.jmsDirection = jmsDirection;
this.cdmCode = cdmCode;
}
作为演示,如果你不引用这些,例如,如果你在两个 subclass 方法中 return 常量,你的代码实际上会 运行很好:
override fun packageName() = "foo"
override fun processName() = "Worker"
但是,您在这里需要的解决方案最有可能使 processFullName
属性 本身变得惰性,而不是它使用的两个值(无论如何您现在正在构造函数时评估,所以你不会利用它们来偷懒)。这意味着您甚至不需要将这两个作为单独的属性:
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
val processFullName by lazy { "$moduleName/${packageName()}.${processName()}" }
protected abstract fun packageName(): String
protected abstract fun processName(): String
}
我正在尝试构建一个具有在子类中初始化的属性的字符串。
我阅读了有关延迟初始化的内容,但不知何故这并没有像我预期的那样工作。
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
private val packageName by lazy { packageName() }
private val processName by lazy { processName() }
val processFullName: String = "$moduleName/$packageName.$processName"
protected abstract fun packageName(): String
protected abstract fun processName(): String
}
class WorkerFullNameBuilder(
private val jmsDirection: JmsDirectionEnumeration,
technicalDomain: TechnicalDomainEnumeration,
private val cdmCode: String) : SubProcessFullNameBuilder(technicalDomain) {
override fun packageName() = "$moduleName.workers.${jmsDirection.value().toLowerCase()}.${cdmCode.toLowerCase()}"
override fun processName() = "Worker"
}
因为我已经覆盖了 packageName()
和 processName()
属性,我希望在调用 packageName
属性 时它会使用子类的实现。
但是当我调用 processFullName
属性 时,它会抛出 java.lang.NullPointerException
.
val builder = WorkerFullNameBuilder(JmsDirectionEnumeration.ESB_IN, TechnicalDomainEnumeration.INFOR, "ccmd")
val name = builder.processFullName
如何以正确的方式初始化 packageName 和 processName 属性?
这是 calling a non-final method in a constructor 的情况,因此访问未初始化的变量。
这一行还在热切的求值,建基class的时候:
val processFullName: String = "$moduleName/$packageName.$processName"
要获取两个惰性属性的值,这将调用抽象方法,其中 packageName()
指的是 jmsDirection
和 cdmCode
指的是 return它的值 - 这些属性尚未初始化,因为它们的值是在 超级class 构造函数 运行 之后设置的。这是 subclass' 构造函数的简化版本,反编译回 Java:
public WorkerFullNameBuilder(@NotNull JmsDirectionEnumeration jmsDirection, @NotNull TechnicalDomainEnumeration technicalDomain, @NotNull String cdmCode) {
super(technicalDomain);
this.jmsDirection = jmsDirection;
this.cdmCode = cdmCode;
}
作为演示,如果你不引用这些,例如,如果你在两个 subclass 方法中 return 常量,你的代码实际上会 运行很好:
override fun packageName() = "foo"
override fun processName() = "Worker"
但是,您在这里需要的解决方案最有可能使 processFullName
属性 本身变得惰性,而不是它使用的两个值(无论如何您现在正在构造函数时评估,所以你不会利用它们来偷懒)。这意味着您甚至不需要将这两个作为单独的属性:
abstract class SubProcessFullNameBuilder(technicalDomain: TechnicalDomainEnumeration) {
protected val moduleName = "td.${technicalDomain.value().toLowerCase()}.shared"
val processFullName by lazy { "$moduleName/${packageName()}.${processName()}" }
protected abstract fun packageName(): String
protected abstract fun processName(): String
}