簡體   English   中英

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屬性?

這是在構造函數調用非最終方法並因此訪問未初始化的變量的情況。

在構造基類時,仍會急切地評估此行:

val processFullName: String = "$moduleName/$packageName.$processName"

要獲取這兩個惰性屬性的值,將調用抽象方法,其中packageName()引用jmsDirectioncdmCode返回其值-這些屬性尚未初始化,因為它們的值是超類構造函數之后設置的運行。 這是子類的構造函數的簡化版本,已反編譯回Java:

public WorkerFullNameBuilder(@NotNull JmsDirectionEnumeration jmsDirection, @NotNull TechnicalDomainEnumeration technicalDomain, @NotNull String cdmCode) {
    super(technicalDomain);
    this.jmsDirection = jmsDirection;
    this.cdmCode = cdmCode;
}

作為演示,例如,如果您不引用它們,例如,如果您在兩個子類方法中都返回常量,則您的代碼實際上可以正常運行:

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM